Go Down

Topic: SPI-Schnittstelle in ISR nutzen? (Read 695 times) previous topic - next topic

Simon12

Hallo zusammen,
ich versuche derzeit eine Vibrationsüberwachung mit einem ADXL362 Beschleunigungssensor zu realisieren. Der Sensor bietet die Möglichkeit einen Interrupt auszulösen wenn ein gewissen Wert überschritten bzw. unterschritten wird. Das würde ich nun gerne ausnutzen und den Arduino schlafen legen und beim unterschreiten bzw. überschreiten eines Wertes aufwecken. Allerdings will ich das nicht gleich beim ersten Interrupt sondern z.B. beim 5. tun. Und hier fangen die Probleme an: Um den Interrupt zu resetten muss das Statusregister des Sensors gelesen werden. Das lesen über SPI wollte ich jetzt in die ISR integrieren damit der Arduino weiterschlafen kann. Im Internet hab ich gelesen, dass eine Kommunikation über SPI in der ISR nicht möglich ist?! Mich würde jetzt interessieren ob das an der Arduino SPI-Library liegt oder ob das bei den ATmegas bzw. generell bei Mikrocontroller nicht vorgesehen ist. Meine Idee wäre jetzt das Lesen des Registers ohne SPI-Schnittstelle zu machen indem man einfach den Timer nutzt und sich die nötigen Signale quasi selber „bastelt". Kann das funktionieren oder ist das vom Timing her zu kompliziert? Habe mich ehrlich gesagt noch nie näher mit den Signalen und dem Timing der SPI-Schnittstelle beschäftigt.
Vielen Dank und viele Grüße
Simon

Serenifly

Das hat wahrscheinlich etwas damit zu tun dass sich auf dem AVR Interrupts nicht gegenseitig unterbrechen können. Beim Eintritt in eine ISR werden die Interrupts gesperrt. Das kann man zwar manuell aktivieren (über das globale Interrupt Enable Flag), aber das kann auch schnell in die Hose gehen.

Eine Alternative die oft funktioniert ist einfach in der ISR ein Flag zu setzen und dann darauf in loop() abzufragen. Die ISR teilt also dem Haupt-Code mit etwas zu tun wenn eineInterrupt angekommen ist. Das sollte auch hier funktionieren.

pylon

Quote
Das lesen über SPI wollte ich jetzt in die ISR integrieren damit der Arduino weiterschlafen kann.


Der Arduino kann nicht schlafen, wenn er eine ISR abarbeiten muss, das sind ja auch Prozessoranweisungen.

Quote
Im Internet hab ich gelesen, dass eine Kommunikation über SPI in der ISR nicht möglich ist?!


Das ist falsch, im Gegenteil ist die SPI-Schnittstelle die einzige serielle Verbindung des Arduinos, die gefahrlos innerhalb einer ISR angesteuert werden kann, da sie für ihre Funktionalität nicht auf Interrupts angewiesen ist.

Quote
Meine Idee wäre jetzt das Lesen des Registers ohne SPI-Schnittstelle zu machen indem man einfach den Timer nutzt und sich die nötigen Signale quasi selber „bastelt". Kann das funktionieren oder ist das vom Timing her zu kompliziert?


Das hingegen funktioniert nicht, da für die Timer Interrupts notwendig sind und diese innerhalb des ISR deaktiviert sind. Wenn Du es so lösen willst, musst Du so vorgehen, wie Serenifly es beschrieben hat (Flag setzen und in loop() darauf reagieren).

Simon12

Danke für die Antworten! War die letzten Tage leider zu beschäftigt um zu antworten. Mit folgendem Code habe ich versucht die SPI-Schnittstelle in der ISR anzusprechen:
Code: [Select]

attachInterrupt(1, reset, RISING);
void reset() {
  SPI.begin();
  SPI.setDataMode(SPI_MODE0); //CPHA = CPOL = 0    MODE = 0
  delay(10);
  digitalWrite(slaveSelectPin, LOW);           
  SPI.transfer(0x0B);  //  write
  SPI.transfer(0x0B);  //  Reg 20 THRESH_ACT_L
  SPI.transfer(0x00);
  digitalWrite(slaveSelectPin, HIGH);
  SPI.end();
}

Sollte doch eig. so funktionieren? Oder muss die Schnittstelle schon vorher initialisiert sein?

Gruß, Simon

Serenifly

delay() funktioniert in einer ISR schon mal nicht, da das selbst mit einem Timer Interrupt läuft. delayMicroseconds() geht, da das steht dessen inline Assembler NOPs in einer for-Schleife macht.

Ansonsten kann es in der Tat besser sein die SPI Schnittstelle nur einmal ein setup() zu initialisieren.

pylon

Den Delay kannst Du Dir sparen, die Hardware benötigt ihn nicht (allenfalls der Slave, aber wenn Du die Initialisierung in den setup() legst, sollte selbst das hinfällig sein). delayMicroseconds() würde zwar im Interrupt-Handler funktionieren, aber 10'000µs in einem Interrupt-Handler zu warten, grenzt schon fast an ein Verbrechen :-). Die Interrupt-Routinen sollten so kompakt und schnell wie möglich programmiert sein, sonst wirst Du ganz schnell viele unerwartete Nebeneffekte kriegen.

chris_86

hi..funktioniert die Verwendung der PSI Schnittstelle in einer ISR jetzt eigentlich...steh vor dem selben Thema? lg

Go Up