Asche auf mein Haupt, aber irgendwie habe ich es immer noch nicht
verstanden, wie ich mit Arrays im Interrupt umgehen muss...
Das Array mit den Zählern für die einzelnen Parameter ist (noch) nicht
volatile, der allgemeine Zähler schon.
Folgende Ausgangssituation für Timeouts:
[1]
1
#define FAIL_ABSMAX 200
2
3
//global:
4
uint16_tFailCnt[3]={0,0,0};
5
volatileuint8_tFailGen;
6
7
voidIRQ(void)
8
{
9
//timeout
10
for(uint8_ti=0;i<3;i++){
11
if(FailCnt[i]<FAIL_ABSMAX){
12
FailCnt[i]++;
13
}
14
else{
15
Input[i]=0;
16
FailCnt[i]=0;
17
}
18
}
19
20
if(FailGen<FAIL_ABSMAX){
21
FailGen++;
22
}
23
}
24
25
26
voidfunction(void){
27
//...receive something and set flag
28
if(received==1){//received successfully
29
FailGen=0;
30
31
if(Param==0){
32
...
33
Input[0]=...;
34
FailCnt[0]=0;
35
}
36
elseif(Param==1){
37
//...
38
Input[1]=...;
39
FailCnt[1]=0;
40
}
41
elseif(Param==2)){
42
//...
43
Input[2]=...;
44
FailCnt[2]=0;
45
}
46
}
47
48
if(FailGen>FAIL_ABSMAX){
49
//timeout -> do something
50
//...
51
}
52
}
Der allgemeine Zähler FailGen sollte so OK sein.
Bei dem Array muss ich wohl auch etwas tun, aber ein
[2]
1
volatileuint16_tFailCnt[3]={0,0,0};
hilft wohl nicht, so wie ich es verstanden habe...
Außerdem müsste
[3]
1
FailCnt[0]=0;
wohl auch noch atomic gemacht werden, da FailCnt ein uint16_t ist, oder?
Muss ich jetzt wirklich mit extra volatile Flags arbeiten, oder gibt es
noch andere Wege?
[4]
1
//global:
2
uint16_tFailCnt[3]={0,0,0};
3
volatileuint8_tFailCnt0Reset;
4
volatileuint8_tFailCnt1Reset;
5
volatileuint8_tFailCnt2Reset;
6
volatileuint8_tFailGen;
7
8
voidIRQ(void)
9
{
10
//timeout
11
if(FailCnt0Reset)
12
FailCnt[0]=0;
13
if(FailCnt1Reset)
14
FailCnt[1]=0;
15
if(FailCnt2Reset)
16
FailCnt[2]=0;
17
18
for(uint8_ti=0;i<3;i++){
19
if(FailCnt0Reset)
20
FailCnt[0]=0;
21
if(FailCnt[i]<FAIL_ABSMAX){
22
FailCnt[i]++;
23
}
24
else{
25
Input[i]=0;
26
FailCnt[i]=0;
27
}
28
}
29
30
if(FailGen<FAIL_ABSMAX){
31
FailGen++;
32
}
33
}
34
35
36
voidfunction(void){
37
//...receive something and set flag
38
if(received==1){//received successfully
39
FailGen=0;
40
41
if(Param==0){
42
...
43
Input[0]=...;
44
FailCnt0Reset=1;
45
}
46
elseif(Param==1){
47
//...
48
Input[1]=...;
49
FailCnt1Reset=1;
50
}
51
elseif(Param==2)){
52
//...
53
Input[2]=...;
54
FailCnt2Reset=1;
55
}
56
}
57
58
if(FailGen>FAIL_ABSMAX){
59
//timeout -> do something
60
//...
61
}
62
}
Das erscheint mir sehr unelegant...
Spielt es eigentlich für die mögliche falsche Optimierung eine Rolle, ob
die Abfrage (if <) im IRQ sitzt und im "normalen" Programm nur eine
Zuweisung gemacht wird, oder andersherum?
Dieter S. schrieb:> hilft wohl nicht, so wie ich es verstanden habe...
hilft nicht - WOGEGEN?
> wohl auch noch atomic gemacht werden, da FailCnt ein uint16_t ist, oder?
korrekt
> Spielt es eigentlich für die mögliche falsche Optimierung eine Rolle, ob> die Abfrage (if <) im IRQ sitzt und im "normalen" Programm nur eine> Zuweisung gemacht wird, oder andersherum?
In der Theorie nicht, in der Praxis schon.
Denn mit Eintritt in die ISR geht der Compiler sowieso nicht davon aus,
dass irgendeine Variable bereits in einem Register sitzen würde. Und da
im Normalfall auf einem AVR eine ISR nicht von einer anderen ISR
unterbrochen wird, spielt es keine Rolle, wenn der Compiler die
Variablenverwendung innerhalb der ISR in der Registerbelegung optimiert.
Eine ISR ist aus Compilersicht eine normale Funktion und deren
Seiteneffekte müssen auf jeden Fall beim Beendigen der Funktion
abgeschlossen sein. D.h. wenn die ISR durch ist, sind auch die Variablen
im SRAM mit Sicherheit wieder alle up to date.
Anders sieht es aber in der Hauptschleife in main() aus.
Dieter S. schrieb:> Asche auf mein Haupt, aber irgendwie habe ich es immer noch nicht> verstanden, wie ich mit Arrays im Interrupt umgehen muss...
Mit Arrays geht man in der ISR genauso um wie mit anderen Variablen.
Dieter S. schrieb:> Bei dem Array muss ich wohl auch etwas tun, aber ein> [2]volatile uint16_t FailCnt[3]={0,0,0};> hilft wohl nicht, so wie ich es verstanden habe...
Was ist dieses "es", das du so verstanden hast? Im Prinzip muß alles,
auf das du sowohl von innerhalb als auch von außerhalb der ISR
zugreifst, volatile sein.
> Außerdem müsste> [3]FailCnt[0]=0;> wohl auch noch atomic gemacht werden, da FailCnt ein uint16_t ist, oder?
Ja.
> Muss ich jetzt wirklich mit extra volatile Flags arbeiten, oder gibt es> noch andere Wege?
Was sind "extra volatile Flags"?
Karl Heinz schrieb:>> hilft wohl nicht, so wie ich es verstanden habe...>> hilft nicht - WOGEGEN?
In einem Beitrag habe ich gelesen, dass das volatile vor dem Array nur
etwas bringt, wenn man das ganze Array übergibt, nicht aber, wenn man
wie ich, auf einzelne Elemente zugreift.
Rolf Magnus schrieb:>> Muss ich jetzt wirklich mit extra volatile Flags arbeiten, oder gibt es>> noch andere Wege?>> Was sind "extra volatile Flags"?
So wie unter [4] gezeigt.
Ich ändere in der Hauptschleife das Array nicht, sondern nur noch im
IRQ.
In der Hauptschleife ändere ich nur eine volatile Variable, die ich dann
auch im IRQ auswerten kann.
Karl Heinz schrieb:>> Spielt es eigentlich für die mögliche falsche Optimierung eine Rolle, ob>> die Abfrage (if <) im IRQ sitzt und im "normalen" Programm nur eine>> Zuweisung gemacht wird, oder andersherum?>> In der Theorie nicht, in der Praxis schon.> Denn mit Eintritt in die ISR geht der Compiler sowieso nicht davon aus,> dass irgendeine Variable bereits in einem Register sitzen würde. Und da> im Normalfall auf einem AVR eine ISR nicht von einer anderen ISR> unterbrochen wird, spielt es keine Rolle, wenn der Compiler die> Variablenverwendung innerhalb der ISR in der Registerbelegung optimiert.> Eine ISR ist aus Compilersicht eine normale Funktion und deren> Seiteneffekte müssen auf jeden Fall beim Beendigen der Funktion> abgeschlossen sein. D.h. wenn die ISR durch ist, sind auch die Variablen> im SRAM mit Sicherheit wieder alle up to date.>> Anders sieht es aber in der Hauptschleife in main() aus.
Könnte der Compiler in Beispiel [1] nicht das FailCnt[0]=0;
wegoptimieren, weil er denkt, dass diese Variable eh nie benutzt wird?
Alles weitere passiert ja im IRQ...
Ich bin jetzt immer noch nicht ganz sicher...
Reicht volatile uint16_t FailCnt[3]={0,0,0}; doch, oder muss ich doch so
Verenkungen wie unter [4] machen, oder ganz anders?
Dieter S. schrieb:> Reicht volatile uint16_t FailCnt[3]={0,0,0}; doch, oder muss ich doch so> Verenkungen wie unter [4] machen, oder ganz anders?
Volatile muß es schon sein. Warum du glaubst, diese Flags zu brauchen,
weiß ich allerdings nicht. Worauf du halt noch achten mußt, ist, wie du
schon sagt, daß der Zugriff aus dem Hauptprogramm atomar erfolgen muß,
also mit gesperrten Interrupts. Das hat aber alles eigentlich nichts
damit zu tun, daß es sich um ein Array handelt. Und im Bezug darauf:
Dieter S. schrieb:> In einem Beitrag habe ich gelesen, dass das volatile vor dem Array nur> etwas bringt, wenn man das ganze Array übergibt, nicht aber, wenn man> wie ich, auf einzelne Elemente zugreift.
Was meinst du denn mit "das ganze Array übergeben"? Wie und wohin soll
man das denn als ganzes übergeben?
Rolf Magnus schrieb:> Warum du glaubst, diese Flags zu brauchen,> weiß ich allerdings nicht.
Ich hatte unten genannten Link gelesen, was mich aber eigentlich mehr
verwirrt hat.
Beitrag "Re: Warnung bei volatile (AVR-GCC)"
Daraus ist dann die Frage mit den volatile Flags enstanden...
Ich versteh immer noch nicht, warum du denkst, dass (mal abgesehen vom
atomar-Problem) ein
>
1
>volatileuint16_tFailCnt[3]={0,0,0};
2
>
> hilft wohl nicht, so wie ich es verstanden habe...
Nichts helfen soll.
In dem Codeteil, den du im Eröffnungsposting angegeben hast, ist das
doch die Lösung. Was soll da jetzt 'nicht helfen'?
Es macht genau das, was man erwartet und was man auch braucht: Es teilt
dem Compiler mit, dass er bei FailCnt immer auf die Werte zugreifen muss
und sich keine Optimierungen erlauben darf.
Genau das, was man zur Kommunikation Hauptprogramm/ISR auch braucht.
Ok, ok.
Ich hatte nach "volatile array" gesucht und u.a. den von mir eben
geposteten Beitrag gefunden. Ich habe wohl nicht verstanden worum es da
geht, aber das hat bei mir den Eindruck erweckt, dass es bei Arrays eben
nicht so einfach mit einem volatile davor getan ist.
Aber wenn dem so ist, umso besser.
Vielen Dank für die Klarstellung.