Welche LIB nutzt/braucht eigentlich welche Interrupt's ?

Kleine Vorgeschichte:
Nach einem Umzug vor einigen Jahren schlummern meine RC-Heli's im Keller und neulich bei einer Aufräumaktion hab ich den gtanzen Kram wieder ausgebuddelt und nun steht alles hier im Bastel-Buden-Büro kreuz und quer und wartet auf Reaktivierung ....
Die mittlerweile steinzeit-ähnliche (aber immer noch sehr gut funktionierende) Steuer-Elektronik soll nun für mehr Komfort und Nutzen durch/mit einem Arduino MEGA ersetzt/erweitert werden, der mir unter Zuhilfenahme einer 2. Sendestrecke dann auch Telemtrie- & Copter-Daten senden soll
.... ja ich weiß: So was gibts es schon lange in verschiedenensten Formen .... aber halt nicht so, wie ich das haben will und dazu hat der Basteltrieb mit dem Arduino wieder neues Feuer bekommen. Und preiswert soll es denn dann auch sein .... (das Material - von der Zeit spricht keiner)

Ich hab mir dazu mal ein großes Blockschaltbild mit allen denkbaren Komponenten und deren möglichen Werte angelegt. Das wären z.B.:

  • Spannungs-, Strom- und Temperaturmessung von Elektronik- und Flug-Akku (LiPo - mit Einzelspannungsmessung !)
  • Drehwinkel- (effektiv und in Echt-Grad), Beschleunigung, Höhenangabe und Position via GPS. Alles X/Y/Z.
  • Echte Rotordrehzahl (Hall oder Licht), Bodenabstand mit Ultraschall, Positions- und Landelichter, Signalgeber, u.v.m
  • ... und den Telemetrie-Sender nebst möglicher Kamera-Steuerung (X/Y) nicht vergessen !
    Das alles scheint mit bereits ausgewählten Komponenten mechanisch/elektrisch wundervoll an den MEGA zu passen. Die Mütze ist dann aber auch fast voll.

Softwareseitig scheint ja auch so weit alles mit vorhandenen LIBs klar. Ich brauche !?:

  • "Wire" betreff I²C für den "Gyro" (6050, 5993, BMP085)
  • "SPI" für den Telemetrie-Sender
  • "Servo" für eben besagte Teile
  • eine 2. Serielle für das GPS
  • einen Interrupt solo für die Auswertung des PPM-Signals vom "Alt-Sender" -> mach ich selber, INT muss ein 16-Bit sein, ist wählbar !
  • und / oder etwas mit "PCInt" ...

Bitte macht mich mal schlau, wie und ob das überhaupt auf der Arduino-Seite zu "Händeln" ist !? :astonished: 8)

Du bist übrigens nicht unbedingt auf die festgelegten Interrupt-Pins beschränkt. Auf dem Atmega kann jeder Pin einen Interrupt auslösen. Der Haken dabei ist, dass die Pins in Registern zusammengefasst sind und sich alle Pins in einem Register den gleichen Interrupt-Vektor teilen, d.h. man muss in der ISR abfragen welcher Pin den ausgelöst hat.

Oder man verwendet das hier (da gibts vielleicht auch noch andere Libs):
http://playground.arduino.cc/Main/PinChangeInt

Ja ja - schon klar ... das wusste ich bereits durch eifriges lesen. 8)
Aber wie ist das bezüglich den fertigen LIBs "SPI" und "Wire" und der Einrichtung einer 2. Seriellen ?
Muss oder kann ich da ggf. benötigte IR's per #define in der jeweiligen Header-Datei auf andere beim MEGA umleiten ?
Ich hab da echt (noch) keinen Plan ...

Ich sehe nicht wo sich das in die Quere kommen sollte. Alles was in Hardware ausgeführt ist hat intern seine eigenen Interrupts, d.h. die zweite serielle Schnittstelle ist schon von sich aus von der anderen getrennt. Auf dem Mega haben die mit Serial1, Serial1 und Serial3 sowieso getrennte Namen.

Und SPI und I2C sind Busse. Das wird einmal initialisiert und andere Geräte werden einfach mit anderen Adressen angesprochen.

Wo man hier u.U. vielleicht eher aufpassen muss ist ob und welche Timer von den Libs verwendet werden.

Ähm, ich frag dann mal anders herum:

Wenn ich ein standard "Serial.begin(115200)" ablasse, welcher INT mit welchen Registern ist denn dann belegt ?
Dito bei

  • "SPI.begin"
  • "Wire.begin"
    ? ? ?

... dann komm ich noch dümpelhaft daher und sage: "INT 0 ist für meine PPM-Erkennung und INT ? für meine Servo's" ?
... das kann und wird doch mit an Sicherheit grenzender Wahrscheinlichlkeit in die Hose gehen - oder ?
... weil sich die Zuweisungen der INT's dann überlappem / stören.
SERIAL sagt: ich brauche ....
SPI sagt: ich brauche ....
WIRE sagt: ich brauche ....
Ich sage: ich brauche und nehme und verändere nach meinem al Gusto ...

Chaos vorprogrammatiert ?!

INT0 und INT1 sind die externen Interrupts.

Das ganze interne Hardware Geraffel wie Timer und Schnittstellen hat alles eigene Interrupts. Diese sind in der Hardware fest vorgegeben. Das hat nichts miteinander zu tun und die Interrupt-Vektoren können nicht per Software geändert oder überhaupt festgelegt werden.

Ich weiß du bist auf dem Mega, aber ich nehme mal den Atmega328P, da ich hier gerade das Datenblatt habe und der grundlegende Aufbau gleich ist:
Auf Seite 65, Table 11-6 steht die Interrupt-Vektor Tabelle:

INT0: 0x02
INT1: 0x04
SPI: 0x22
RX: 0x24
TX: 0x28
TWI: 0x30

Also alles getrennt. Der Mega hat für zusätzliche Schnittstellen dann einfach mehr Interrupt-Vektoren. Ein Interrupt-Vektor ist nur eine Programm Adresse. Wenn ein Interrupt kommt, springt das Programm an die entsprechende Adresse. Da steht dann ein absoluter Jump auf die Adresse der ISR.

............. na um das interne geht es mir auch (eben) nicht !
Lass den Vektoren seine Adressen .............

Mir geht es hier um die DOPPEL-BELEGUNG / RE-INITIALISIERUNG von Interrupts !

D. h. wie oben gesagt: Wer belegt bereits standardmäßig was und was ist noch für was anderes frei .... und wie zu belegen ?

Die Frage wie ebenso o.g. dazu:
-> Kann man fertige LIBs (Serial, Wire, SPI u. a.) auch dazu überreden, andere INT's zu nutzen ?

Doch, genau darum geht es. Was will da doppelt initialisiert werden wenn die Vektoren fest stehen? Diese Libs (TWI, SPI, Serial) haben gar keine Wahl welche Interrupts sie verwenden. Das ist alles in der Hardware fest und kann nicht kollidieren (außer zeitlich natürlich).

Das wäre nur relevant wenn du sagen wir mal zwei spezielle Hardware-Libs hättest und die bräuchten beide externe Interrupts. Dann könnte es vielleicht vorkommen, dass beide INT0 verwenden (man könnte dann eine auf INT1 ändern). Aber für die Standard Kommunikations-Schnittstellen muss man sich da keine Gedanken machen.

Serenifly:
Doch, genau darum geht es. Was will da doppelt initialisiert werden wenn die Vektoren fest stehen?

Genau eben darum !
Z.B. gehe ich nun mal daher - habe SPI, WIRE & Co. eingebunden - und sage einfach mal so in meinem Code:

  • INT0 ist meiner zum Erkennen des PPM-Signals
  • INT1 nehme ich mal zur Steuerung meiner Servos's
  • INT2 sagt mir z.B. das der Akku gleich leer ist
    usw.

Da überschreibe ich doch definitiv vorhandene "Ansprüche" von Serial, SPI und Wire - oder nicht ?

Nein. Was haben denn die externen Interrupts mit Wire oder SPI zu tun? Die haben ganz andere Interrupt-Adressen. Das wollte ich ja mit der Interrupt-Vektor Tabelle erklären.

Wenn ein Interrupt auf INT0 kommt springt das Programm auf 0x02 (beim Atmega328). Wenn ein Interrupt auf dem I2C Bus kommt, springt das Programm zu 0x30. Wenn du attachInterrupt() machst, wird an dieser Stelle nur die Adresse deiner Interrupt-Methode eingetragen, so dass das Programm dann über die Vektor Tabelle in die Methode springt. Da wird nichts überschrieben.

EDIT:
Gerade mal nachgeschaut und die ISR deaktiviert auf dem AVR automatisch das globale Interrupt Enable Flag, d.h. Interrupts werden nicht von einem anderen unterbrochen. Da hatte ich vorher was anderes gesagt. Das ist bei anderen Architekturen zum Teil anders. Wenn du gerade einen Serial Interrupt abarbeitest und es kommt während dessen ein anderer Interrupt wird dieser nach beenden der Serial-ISR abgearbeitet. Niedrigere Vektoren haben dabei eine höhere Priorität falls mehrere Interrupt-Flags gesetzt sind (das ist der Grund weshalb die externen Interrupts soweit vorne stehen). Also stört sich auch zeitlich nichts.

In deinem speziellen Fall geht es eher um die hardware-timer, derer 3 es gibt (beim atmega 168/ 328) als die entsprechenden Interrupts.

Hmm .... irgendwie hab ich das nocht ganz auf dem Schirm. Noch mal gefragt:

  1. An Pin D2 will ich das PPM-Signal meines RC-Senders einlesen.
    Dazu nehme ich nun z.B. aus der LIB RCArduinoFastLib die Funktionen der Klasse CRCArduinoPPMChannels.
    Standardmäßig wird initialisiert mit attachInterrupt(0,CRCArduinoPPMChannels::INT0ISR,RISING); und eine eigene ISR eingetragen.

  2. Um nach der "Behandlung" der Servo-Signale diese auch weiterzugeben, setze ich die Servo-Lib ein.
    Wenn ich das richtig erkannt habe initialisiert die - sofern man nicht anderes im Header einstellt - INT5 bzw. INT1.

Soweit so gut im Gedankenspiel, solte zusammen funtkionieren. Ausprobiert hab ich das in der Kombi noch nicht.

  1. Nun noch mit SoftwareSerial einen 2. Port aufgemacht, um mit dem GPS-Modul zu sprechen.
    Hier kann / darf man ja nur bestimmte Pins belegen lt. Angabe - u.a. auch 50 - 53, was beim MEGA ja SPI wäre ?! Ich würd dann mal 10/11 nehmen.
    Welcher INT wird denn hier belegt ? Kann ich das auch vorgeben ?
    Ich lese im Source was von #if defined(PCINT0/1/2/3_vect) - aber wo wird das definiert ?
    INT0 und INT1 sind doch bereits belegt. S.o.

  2. Wire bräuchte ich dann noch, um mit dem Gyro/Barometer zu kommunizieren.
    Das läuft über einen internen IRQ ? Keine Kümmerung notwendig ?

  3. Last but not least wird der Transceiver via SPI bedient.
    Auch hier interner IRQ, so das mich das nicht jucken muss ?

Sprich: Normalerweise sollte alles brav und artig zusammenspielen und der MEGA kocht ....
Hab ich das so korrekt auf der Lampe ?
Bleiben die Frage zu 3).

Du solltest dir halt generell darüber im Klaren sein, dass die ganze Interrupt-Logik in Hardware ausgeführt ist (Dadurch ist die erste Anlaufstelle wenn man rausfinden will wie das funktioniert auch das Datenblatt des Prozessors). Deshalb hat das mit den Libs an sich wenig bis nichts zu tun. Das meiste ist eben festgelegt, vor allem 4) und 5), aber auch 1) je nachdem was du da bei attachInterrupt angibst

Das funktioniert solange du verschiedene externe Interrupts für jene Libs verwendest die das brauchen (was bei 1) und 2) der Fall ist). Wenn du also für 1) INT0 verwendest und 2) dann INT1 oder INT5 nimmt, passt das. Die Zuordnung von externen Interrupts zu Arduino Pins ist aus dem Pin-Mapping ersichtlich:


http://forum.arduino.cc/index.php?topic=45329.msg328678#msg328678

EDIT:
So wie das da auf dem Bild steht gibt es da doch Konflikte. Und zwar nicht mit den Interrupt-Vektoren oder irgendwelchen Registern, sondern den Pins. INT0 und INT1 liegen auf der I2C/TWI Schnittstelle (43,44), und INT2 und INT3 (45,46) liegen auf Serial1 - nicht zu verwechseln mit Serial (Pins 2 und 3 oben links). Also INT0 und INT1 sollte man dann doch nicht verwenden!! INT2 und INT3 sind frei wenn man Serial1 nicht verwendet. INT4 und INT5 (Pins 6 und 7) sind mit Timer 3 geteilt, also frei wenn da keine PWM drauf läuft. INT6 und INT7 gibt es auf dem Chip, aber sind leider nicht herausgeführt.

Das hättest du aber spätestens beim Anschließen der Leitungen gemerkt :slight_smile:
Der Mega hat da mehrere so komische Sachen. z.B. ist nur ein Pin des Analog-Komparators herausgeführt. Anscheinend wollte man die Arduino-Platine nicht noch größer machen und hat nicht alles angeschlossen. Beim Uno/Atmega328 ist das nicht der Fall. Und keine Ahnung wieso Atmel nicht INT0 und INT1 einfach auf einen der I/O Ports gelegt hat die keine spezielle Funktion haben.

Auch seltsam ist, dass die Arduino IDE eine ganz andere Nummerierung für die Interrupts hat (deshalb Vorsicht welche Bezeichnung man da verwendet!):
http://arduino.cc/en/Reference/AttachInterrupt
Was da als Int.2 und Int.3 bezeichnet wird, heißt auf dem Chip INT0 und INT1. Int.0 ist INT4, Int.1 ist INT5, Int.4 ist INT2 und Int.5 ist INT3 :o

Wenn du attachInterrupt(0, ...) machst hängst du also tatsächlich an INT4, bzw. Pin 6 (auf dem AVR. Der Arduino Pin ist 2).

Zusammenfassung: verwende INT2 bis INT5 (AVR Bezeichnung) für deine externen Interrupts und beachte die seltsame Zuordnung der attachInterrupt() Funktion. Int.2 und Int.3 (Arduino Bezeichnung) liegen auf den I2C Pins. Int.0, Int.1, Int.4 und Int.5 sind frei.

Dann zu Software Serial:

So wie das hier steht...: http://arduino.cc/en/Reference/SoftwareSerial

...läuft das über die Pin-Change Interrupts (die ich in meiner ersten Antwort erwähnt habe). Es geht also auf allen Pins, die Pin-Change Interrupts machen. Das sind auf dem Mega nicht alle, weshalb es da Einschränkungen gibt.

Zu "#if defined(PCINT0/1/2/3_vect)":
"INT0" und "INT1" sind die externen Interrupts (die jeweils auf einem ganz bestimmten Pin sind). Nicht zu verwechseln mit "PCINT0" und "PCINT1" welche Pin-Change Interrupts sind. Das habe ich auch nicht gleich gewusst, aber es ist aus dem Datenblatt ersichtlich (in der Interrupt-Vektor Tabelle sind die Bezeichnungen erklärt). Hat also mit den anderen Interrupts nichts zu tun :slight_smile:

Du hast aber auf dem Mega vier(!) serielle Hardware-Schnittstellen. Will die GPS Lib da SoftwareSerial verwenden?

@ Serenifly:

Ich danke dir für deine Geduld, mir ein bis mehr Lichtlein aufzugehen gelassen haben tun und so .... :grin:
Für diese gute Tat an mir und hoffentlich auch anderen Mitlesern sei auch dir ein Licht zuteil.

Ich denke, dass ich das jetzt geschnallt habe !
Das auf dem MEGA 4 serielle Damen hardwareseitig zum Tanz laden, hatte ich gar nicht mehr im Blick ...

Welche GPS-Lib da zum Einsatz kommt, ist noch nicht klar, weil noch kein konkretes Modul hier vorliegt. Ich werde sehen.

Kann ich jetzt also mit Ruhe in meinen Pin-/Beschaltungs-Layout (ich mache das mit ACAD) weiterpfriemeln.
Alles Eile mit Weile - ist ja nun nicht grade mal nen Wochenendprojekt ..... 8)

Ich hab mir nun mal ne Excel-Tabelle gemacht und alle erforderlichen Pins gelistet.
Da macht mich schon wieder was stutzig:

"INT0" und "INT1" sind die externen Interrupts (die jeweils auf einem ganz bestimmten Pin sind).

Die Referenz sagt zu den externen Interrupt-Pin-Belegungen am MEGA:
INT0 -> Pin 2 -> Damit würde ich mein PPM-Signal einlesen
INT1 -> Pin 3 -> Hier käme der INT des Gyros dran (nicht zwingend, aber praktischer)
INT2 -> Pin 21 -> das ist SCL ! (belegt für Gyro/MAG/Baro)
INT3 -> Pin 20 -> das ist SDA ! (belegt für Gyro/MAG/Baro)
INT4 -> Pin 19 -> RX1 -> gedacht für INT des Transceivers (nicht zwingend, aber praktischer)
INT5 -> Pin 18 -> TX1 -> 1. interne Belegung durch die Servo-Lib.

Die Kommunikation mit dem GPS würde ich dann über Serial2 machen - die Pins 16/17 sind so wie das sehe nicht mit was anderem doppeltbelegt.

INT2 und 3 fallen zur externen Ansteuerung wegen I²C-Bus weg.
Kann ich den INT2 dennoch nutzen, um z.B. ein Blinken der Positionslichter zu erzeugen ?
Dito, wenn ich der Servo-Lib konkret mitteile, sie möchte bitte INT3 statt 5 benutzen, hätte ich Pin 18 noch als externen Eingang frei !?

Kann mir bitte mal jemand (Hallo Serenifly !) bestätigen, ob meiner Gedankengänge richtig waren oder bin ich da auf dem "Wood-Way" ?

Du solltest das eher int.x nennen. Dann hast du da Bezeichnungen der Arduino IDE und Referenz, d.h. die Nummer die du bei attachInterrupt() angibst. So wie das da jetzt steht, sind das die AVR Namen. Die sind wie gesagt anders und verwirrend! Oder mach beides in getrennte Spalten.

Der I2C Bus läuft so wie ich das sehe mit 100kHz. Das ist nicht viel was Datenbusse betrifft, aber viel zu schnell um eine LED Blinken zu lassen. Du könntest theoretisch einen Frequenzteiler dahinter hängen, z.B. HC4020. Damit kannst du die Frequenz durch maximal 2^14 teilen (weniger geht auch), was dann ca. 6Hz oder 166ms wären. Ich würde da aber eher einen der Timer verwenden und dann einfach im Timer-Interrupt eine LED toggeln. Oder wenn du eine externe Schaltung willst, NE555. Damit bist du wesentlich flexibler.

Dito, wenn ich der Servo-Lib konkret mitteile, sie möchte bitte INT3 statt 5 benutzen, hätte ich Pin 18 noch als externen Eingang frei !?

int.3 ist doch schon mit I2C Datenleitung belegt.

Schau da mal nach, dass du da nicht AVR-INT5 meinst (was wahrscheinlich der Fall ist wenn du da einfach den Namen der ISR angeguckt hast). Das ist nämlich Arduino int.1 an Pin 3

Diese Zuordnung bekommst du wenn du die Arduino Interrupt Pins hier anschaust:
http://www.jassper.com/images/MEGA1280.jpg (die Nummern innen)
und dann siehst was außen an den Pins des Prozessors steht

.... es wird nicht einfacher ....
Ich meinte die Bezeichnungen so wie sie hier angegeben sind: http://arduino.cc/en/Main/ArduinoBoardADK und auch in den LIBs/Sketchen verwendet wird - nicht die Bezeichnung am Professor.

int.3 ist doch schon mit I2C Datenleitung belegt.

Wie jetzt ?
Hattest du nicht geschrieben, dass das SPI, TWI und Serial hardware-interne IRs benutzt ?
Das die Pins 20/21 als Hardware-Eingang wegfallen ist klar ....
Benutzt der I²C-Bus (läuft übrigend mit 400 KHz) den auf den Clock dann auch INT2 ?

Du warst schon auf dem richtigen Weg:

Arduino Int. | AVR Int. | Arduino Pin | Funktion

int.0 -> INT4 -> Pin 2 -> OC3B
int.1 -> INT5 -> Pin 3 -> OC3C
int.2 -> INT0 -> Pin 21 -> SCL
int.3 -> INT1 -> Pin 20 -> SDA
int.4 -> INT2 -> Pin 19 -> Serial1 RX
int.5 -> INT3 -> Pin 18 -> Serial1 TX

Wir haben da anscheinend nur mit den Bezeichnungen etwas aneinander vorbei geredet :slight_smile: Ich dachte halt, dass die Libs da eher die AVR Namen verwenden wenn das festgelegt ist. Die int.x Konvention des Arduinos wird glaube ich nur bei attachInterrupt() verwendet. Aber wie das da intern gemacht wird habe ich mir nicht angeschaut.

Das die Pins 20/21 als Hardware-Eingang wegfallen ist klar ....

Ich hatte auch die Leitungen gemeint, nicht die Interrupt-Logik :slight_smile:

Benutzt der I²C-Bus (läuft übrigend mit 400 KHz) den auf den Clock dann auch INT2 ?

Ich glaube nicht, denn I2C hat einen eigenen Interrupt-Vektor

Auf dem UNO/Atmega328 liegen die auch nicht zusammen. Nur auf dem Mega.

Wie heisst das so schön: Versuch macht Kluch ! :smiley:
Wenn's soweit ist, pinne ich hier die Bilder vom implodierten MEGA. 8)