i2c_start(busAddr+I2C_READ);// restart as a read operation
7
data=i2c_readNak();// read the register data
8
i2c_stop();// stop
9
sei();
10
returndata;
11
}
Früher gab es ja noch SIGNAL und INTERRUPT (<-- heutige ISR)
SIGNAL hat dabei ja Interrupts während der IR-Routine erlaubt.
Meine Frage wäre daher nun, ob ich mir künstlich wieder ein SIGNAL
gebaut habe, dadurch dass ich in der ISR einen Funktionsaufruf verwende
der sei() enthält?
Oder wird das I-Bit unter keinen umständen verändert, solange ich mich
in der ISR befinde und bin somit safe?
Grüße Oekel
@ D a v i d K. (oekel)
>ich verwende gerade jede Menge I2C Aufrufe. Eine davon sogar im ISR
Naja, hoffentlich ist die ISR-Frequenz nicht zu hoch.
>Nun habe ich pauschal alle I2c_* Funktionen mit einem cli()/sei();>umschlossen.
Warum? Das ist im Normalfall nicht nötig. I2C ist synchron und du nutzt
ja das I2C Modul deines AVRs. Da darf so ein I2C Zugriff auch mal durch
einen ISR unterbrochen werden.
>Früher gab es ja noch SIGNAL und INTERRUPT (<-- heutige ISR)>SIGNAL hat dabei ja Interrupts während der IR-Routine erlaubt.
Alter Kram. Vergiss das.
>Meine Frage wäre daher nun, ob ich mir künstlich wieder ein SIGNAL>gebaut habe, dadurch dass ich in der ISR einen Funktionsaufruf verwende>der sei() enthält?
Nun ja, selbst wenn man eine Funktion atomar ausführen will, sollte man
im Normalfall die Funktionen aus util/atomic.h nutzen. Denn die können
am Ende des atomaren Blocks den vorherigen Zustand des I-Bit wieder
herstellen. Sprioch, wenn es vorher gelöscht war, bleibt es gelöscht!
1
#include<util/atomic.h>
2
3
ATOMIC_BLOCK(ATOMIC_RESTORESTATE){
4
// atomarer Funktionsblock, Interrupts sind gesperrt
5
}
Siehe Doku der libc.
>Oder wird das I-Bit unter keinen umständen verändert, solange ich mich>in der ISR befinde und bin somit safe?
Nö. Ein sei() setzt das I-Bit. Immer.
Du kannst sei() natürlich auch innerhalb einer ISR verwenden. Du
solltest aber auf jeden Fall vor sei() dafür sorgen, dass der aktuelle
Interrupt (Also bei dir der Timer0 Overflow) deaktiviert ist, weil sonst
die Gefahr besteht, dass der Stack überläuft.
Also nach dem Schema
1
ISR(TIMER0_OVF_vect){
2
// whatever
3
TIMSK&=~(1<<TOIE0);
4
sei();
5
// noch mehr Code
6
cli();
7
TIMSK|=1<<TOIE0;
8
return;
9
}
Bei dir ist das aber eigentlich gar nicht sinnvoll, weil du ja keine
Interrupts während deines Timer-Overflows benötigst (Zumindest macht
dein Codeschnipsel den Anschein). Ich würde an deiner Stelle eher das
Statusregister speichern und anschließend wiederherstellen.
Aus dem GCC Tutorial:
Falk B. schrieb:> @ D a v i d K. (oekel)>>>ich verwende gerade jede Menge I2C Aufrufe. Eine davon sogar im ISR>> Naja, hoffentlich ist die ISR-Frequenz nicht zu hoch.
Teiler: 1024
> Nun ja, selbst wenn man eine Funktion atomar ausführen will, sollte man> im Normalfall die Funktionen aus util/atomic.h nutzen. Denn die können> am Ende des atomaren Blocks den vorherigen Zustand des I-Bit wieder> herstellen. Sprioch, wenn es vorher gelöscht war, bleibt es gelöscht!>>
1
>#include<util/atomic.h>
2
>
3
>ATOMIC_BLOCK(ATOMIC_RESTORESTATE){
4
>// atomarer Funktionsblock, Interrupts sind gesperrt
5
>}
6
>
Mein theoretisches Szenario wäre das sich das ganze wie folgt mal michen
könnte:
i2c_start(busAddr+I2C_READ);// restart as a read operation
13
data=i2c_readNak();// read the register data
14
i2c_stop();// stop
15
//sei();
16
//}
17
18
//...weiter gehts
19
i2c_write(data);
20
i2c_stop();
21
sei();
22
}
Sprich es kommt im besten Fall Müll auf dem Display an (dafür verwende
ich das "I2C_WriteRegister") im Schlimmsten Fall hängt er sich auf?
(darartigen Fall habe ich gerade sporadisch in der Praxis und schiebe es
auf den ISR.
(konkret läuft eine Endlosschleife mit Testausgaben: 40-100x ok. dann
steht alles...)
cli und sei in Funktion vermeiden. Maximal im Hauptstrang. oder vorher
fragen, ob Interrupts gesperrt sind. Falls ja, dann nachher nicht
freigegeben. Erfordert aber genaue Überlegungen.
Auch braucht man oft getrennte Funktionen für gleiche Aufgaben: eine für
den Aufruf aus Interrupts.
@D a v i d K. (oekel)
>Mein theoretisches Szenario wäre das sich das ganze wie folgt mal michen>könnte:
Stimmt. Dann braucht man eine atomare Sicherung. Aber in den meisten
Fällen ist es besser, keinerlei I2C Zugriffe in der ISR zu machen und
statt dessen alle Zugriffe nur als normale Funktion in der
Hauptschleife.
https://www.mikrocontroller.net/articles/Interrupt#Steuersignale_zwischen_ISR_und_Hauptprogramm
Das hat auch den Vorteil, daß man sehr langsame Funktionen nutzen kann,
die in einer ISR nichts zu suchen haben.
Falk B. schrieb:> Aber in den meisten> Fällen ist es besser, keinerlei I2C Zugriffe in der ISR zu machen und> statt dessen alle Zugriffe nur als normale Funktion in der> Hauptschleife.
Hatte ich auch ursprünglich nicht vor. Doch wie die Flanken eines
Tasters am HT16K33 rechtzeitig erkennen, wenn ich nicht ständig auf dem
I2C-Bus pulle?
@ D a v i d K. (oekel)
>Hatte ich auch ursprünglich nicht vor. Doch wie die Flanken eines>Tasters am HT16K33 rechtzeitig erkennen, wenn ich nicht ständig auf dem>I2C-Bus pulle?
Man kann die periodische Abfrage (vulgo "pulle") innerhalb einer
Funktion im Hauptprogramm machen. Wie das geht, steht in meinem Link.
Falk B. schrieb:> @ D a v i d K. (oekel)> Man kann die periodische Abfrage (vulgo "pulle") innerhalb einer> Funktion im Hauptprogramm machen. Wie das geht, steht in meinem Link.
Danke, hab es jetzt genau so gelöst.
Die Hauptroutine wirkte anfänglich so riesig, dass ich vermutet habe
"dort muss unbedingt zwischengesprungen werden". Aber tatsächlich wird
jeder REST-Zweig mit 5-6 if-Abfragen erreicht und die vorgelagerte
1
if(flag)
2
alter_ISR_Teil();
3
else
4
REST();
stört den "REST-Ablauf" nicht wirklich.
Endlich wieder Determinismus. Danke!
PS: In der Theorie hatte ich das alles schon gelesen (lese ja viel der
hiesigen Wiki-Artikel). In der Praxis muss man aber immer wieder drauf
gestoßen werden, um seinen Code zu strukturieren.
D a v i d K. schrieb:> Nun habe ich pauschal alle I2c_* Funktionen mit einem cli()/sei();> umschlossen.
"Pauschal" ist immer ein schlechter Programmierstil. Man muß sich bei
jeder Anweisung auch was gedacht haben. Insbesondere Anweisungen
bezüglich der Interruptlogik sollte man nur mit Bedacht einfügen.
Letzte Nachricht von mir diesbezüglich:
Gibt es einen Grund wieso man einen Eröffnungspost negativ bewertet?
Antworten zu markieren finde ich ja logisch, aber "dumme Fragen" gibt es
nicht und die Höflichkeit gebietet es doch nachzuhaken oder des Weges zu
gehen!?