Arduino Mega + Ethernet-Shield + SD + RFM12B hängt sich nach einigen Minuten auf

Hallo, ich wollte jetzt meinen Webserver (Arduino Mega + Ethernet-Shield) um einen RFM12B erweitern. Der bisherige Sketch läuft seit Wochen ohne Unterbrechung. Nun habe ich den RFM12B angeschlossen. Den IRQ habe ich an Pin D2 angeschlossen (INT0). Für den ChipSelect nutze ich statt Pin53 den Pin D5. Dazu habe ich in der Jeelib die entprechenden Einträge geändert. Außerdem habe ich in der Ethernetlib die Interrupts gesperrt. Diese Infos habe ich in diversen Forumbeiträgen gefunden.

Der Sketch funktioniert prinzipiell. Der RFM12B empfängt die Daten und der Webserver + SD-Karte funktioniert auch. Solange ich nicht auf den Webserver zugreife, läuft der Sketch stundenlang fehlerfrei. Wenn ich allerdings eine Webseite jede Minute im Browser refreshen lasse, hängt sich der Sketch nach einigen Minuten oder auch Stunden auf =( Es gibt also ein SPI-Problem, welches allerdings nur sporatich auftritt?

Ich habe versucht, während der Nutzung Ethernet/SD den ChipSelect-Pin vom RFM12 auf HIGH zu setzen, hilft aber nichts. Wenn ich versuche, vor der Nutzung Ethernet/SD das RFM12 in den Sleep-Modus zu setzen und danach wieder aufzuwecken, hängt sich der Sketch beim aufwecken des RFM12 auf?

Hat hier noch jemand eine Idee?

Hat jemand einen Arduino + Ethernetshield + RFM12 am laufen?

Viele Grüße, paulinchen

Hallo,

hat sich das Probelm gelöst? Ich habe im Moment das gleiche Problem und wüsste gerne was die Ursache ist.

Gruß Snoops

Wo ist der Code?

Hier der Code, siehe Anhang weil zu groß zum einbinden…

Gruß
Snoops

MEGA haengt mit RFM12S.txt (25.2 KB)

Kannst Du den Output der seriellen Schnittstelle posten bis dort, wo sich der Arduino aufhängt?

Auf den ersten Blick fällt mir auf, dass Du das F()-Makro nicht verwendest und somit viel wertvollen Speicher verschwendest. Beim Mega sollte das nicht so stark in's Gewicht fallen, aber bei komischen Hängern ist es nicht ausgeschlossen.

Das grösste Problem dürfte die JeeLib sein, denn die konfiguriert die SPI-Schnittstelle auf eine etwas hohe Geschwindigkeit:

void rf12_spiInit () {
    bitSet(SS_PORT, cs_pin);
    bitSet(SS_DDR, cs_pin);
    digitalWrite(SPI_SS, 1);
    pinMode(SPI_SS, OUTPUT);
    pinMode(SPI_MOSI, OUTPUT);
    pinMode(SPI_MISO, INPUT);
    pinMode(SPI_SCK, OUTPUT);
#ifdef SPCR
    SPCR = _BV(SPE) | _BV(MSTR);
#if F_CPU > 10000000
    // use clk/2 (2x 1/4th) for sending (and clk/8 for recv, see rf12_xferSlow)
    SPSR |= _BV(SPI2X);
#endif
#else
    // ATtiny
    USICR = bit(USIWM0);
#endif
    pinMode(RFM_IRQ, INPUT);
    digitalWrite(RFM_IRQ, 1); // pull-up
}

Das setzen der SPI2X-Option beschleunigt die SPI-Schnittstelle auf 8MHz, was für viele Geräte zuviel sein dürfte. Ich bin kein Spezialist für den RFM12B, aber ich glaube nicht, dass er wirklich so hohe Geschwindigkeiten benötigt. Ich würde diese Zeile einfach mal auskommentieren und sehen, ob das die Situation verbessert.

Was meinst du mit F() Macro?

Hier der Ausgabe in der SPI Schnittstelle...

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=0

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=

Der AVR hat eine modifizierte Harvard Architektur. Das heißt Flash und RAM haben getrennte Adressräume und die Standard Funktionen können keine Pointer ins Flash nehmen. Daher werden am Anfang alle String Konstanten aus dem Flash ins RAM kopiert!

AVR gcc bietet da aber einige Makros ein um Werte im Flash zu behalten und mit Pointern ins Flash umzugehen.

Arduino hat darüber hinaus das F() Makro was mit der Arduino Funktion print() geht. Einfach so: Serial.println(F("String im Flash"); Und schon belegt das kein RAM mehr.

Ansonsten kann man sowas machen (hier für ein TFT):

void displayPrint_P(const char* str, int x, int y)
{
  strncpy_P(stringBuffer, str, STRING_BUFFER_SIZE);
  display.print(stringBuffer, x, y);
}

displayPrint_P(PSTR("keine Karte!"), 0, 70);

strcpy_P ist hier nötig um den String vom Flash ins RAM zu kopieren. Dann braucht man nur noch einen Puffer für alles. Die ganzen Standard String Funktionen wie strcmp() oder strlen() haben auch meistens eine _P Version um Strings im Flash direkt zu bearbeiten.

Oder was ich kürzlich gefunden habe:

sprintf_P(stringBuffer, PSTR("%02d:%02d:%02d"), hour(), minute(), second());

Dadurch bleibt der Format-String von printf() im Flash :)

Snoops: Was meinst du mit F() Macro?

Hier der Ausgabe in der SPI Schnittstelle...

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=0

Send Request Header=41 Send Data Lenght=17 Send Request to NodeID=1 von NodeID=3 Send Request RF12_HDR_DST=40 Send Request RF12_HDR_CTL=0 Send Request RF12_HDR_ACK=

Das ist mit Sicherheit nicht der serielle Output des Codes den Du angehängt hast (zwei Send-Blöcke ohne weiteren Output dazwischen kann bei dem Code nicht passieren). Könntest Du bitte den seriellen Output des Codes, den Du angehängt hast, hier vollständig (Du kannst am Anfang Zeilen weglassen, aber von dort, wo Du startest, dürfen keine Zeilen herausgelöscht werden) posten? Hängt er wirklich nach der Ausgabe von "Send Request RF12_HDR_ACK=", ohne dass er die Zahl danach ausgibt?

Hast Du die Zeile

SPSR |= _BV(SPI2X);

in der JeeLib mal auskommentiert? Bringt das was?

Hallo,

uupps - cut and paste Fehler, die Null ist natürlich noch zu sehen!

(zwei Send-Blöcke ohne weiteren Output dazwischen kann bei dem Code nicht passieren)

-->geht schon, wenn die Gegenstelle nicht antwortet - sehe es ja grade selbst :D

Hier nochmal etwas mehr Text aus der seriellen Ausgabe:

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=0

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=0

Bytes empfangen: 17 OK
Header: 63
Data:  01 03 00 00 00 48 40 B5 00 04 00 E1 00 00 00 1C 41
Receive Header: 63  von Node ID: 3  zu Node ID: 3
Receive RF12_HDR_DST=64
Receive RF12_HDR_CTL=0
Receive RF12_HDR_ACK=32
-->ACK Antwort versendet von NodeID: 3
   TempAussen: 3.13
   TempInnen: 9.75
   SensorWert: 181
   Windgeschwindigkeit: 4
   WindRichtung: 225 SO

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=0

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=0

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=0

Send Request Header=41
Send Data Lenght=17
Send Request to NodeID=1 von NodeID=3
Send Request RF12_HDR_DST=40
Send Request RF12_HDR_CTL=0
Send Request RF12_HDR_ACK=0

Die untere Zeile habe ich in der RF12.cpp auskommentiert, leider ohne Erfolg =(

//#if F_CPU > 10000000
    // use clk/2 (2x 1/4th) for sending (and clk/8 for recv, see rf12_xferSlow)
    //SPSR |= _BV(SPI2X);
//#endif

Gruß Snoops

-->geht schon, wenn die Gegenstelle nicht antwortet - sehe es ja grade selbs

Stimmt, der Code war durch die schreckliche Formatierung einfach praktisch unleserlich. Nach einem simplen AutoFormat in der IDE war's deutlich erträglicher.

Solche Sachen solltest Du auch aufräumen:

    digitalWrite(10, LOW);                    // Ethernet SPI Schnittstelle ausschalten.
  }
  digitalWrite(10, LOW);                   // Ethernet SPI Schnittstelle EINschalten.

Falsche Kommentare führen immer wieder in Probleme. Zudem führt die Ethernet-Bibliothek selbst Buch über ihren SS-Pin, Du solltest Dich da also raushalten. Ebenso hier:

  digitalWrite(10, HIGH);              // Ethernet SPI Schnittstelle ausschalten.
  digitalWrite(4, HIGH);                   // SD-Karte ausschalten.

Dieser Code-Teil

    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {

ist falsch, einerseits beschreiben die Kommentare nicht, was der Code wirklich tut (Du sendest die Antwort beim ersten Newline-Zeichen, das Du liest). Andererseits ist schon der Kommentar falsch, das bei der ersten Leerzeile nur der Header des Requests fertig ist, der Request muss deswegen noch nicht komplett sein. Das Einlesen des kompletten Headers wäre zumindest schon angebracht.

Diese Zeile bereitet mir Sorge:

  //rf12_set_cs(10);                              // function to set chip select pin

Wo hast Du den SS-Pin des RFM12B angeschlossen? Auf Pin 10 ist nämlich schon das Ethernet-Shield. Bei einer Doppelbelegung wundert mich das unstabile Verhalten nicht mehr, da wundere ich mich eher, dass überhaupt was ging.

Hallo,

den Ethernet Teil verwende ich seit ca 1 Jahr ohne Problem in einem anderem Programm. Deshalb denke ich , das ist nicht wirklich das Problem zumal sich der Code auch ohne einen Ethernet Request aufhängt.

(Du sendest die Antwort beim ersten Newline-Zeichen, das Du liest). Andererseits ist schon der Kommentar falsch, das bei der ersten Leerzeile nur der Header des Requests fertig ist, der Request muss deswegen noch nicht komplett sein. Das Einlesen des kompletten Headers wäre zumindest schon angebracht.

Dennoch, wie wäre denn der Ethernet Teil korrekt?

Als SS-Pin verwende ich PIN49:

#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)

#define RFM_IRQ    2
#define SS_DDR      DDRL
#define SS_PORT     PORTL
#define SS_BIT      0

Snoops: Als SS-Pin verwende ich PIN49:

#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)

define RFM_IRQ    2

define SS_DDR      DDRL

define SS_PORT    PORTL

define SS_BIT      0

Interessant, denn in der JeeLib (https://github.com/jcw/jeelib) ist das anders definiert:

#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)

#define RFM_IRQ 2
#define SS_DDR DDRB
#define SS_PORT PORTB
#define SS_BIT 0

Was hast Du denn sonst noch verändert? Oder verwendest Du gar eine andere Bibliothek, falls ja, welche? Es bringt nicht viel, wenn ich Code durchschaue, den Du gar nicht verwendest. Ich muss mir wieder angewöhnen, auf Links zu den verwendeten Bibliotheken zu bestehen, Zeit zu vergeuden mit Google-Suchen, die dann doch was anderes zu Tage fördern, ist frustrierend.

Poste auch ein Foto des Aufbaus, eventuell sind da noch andere Sachen versteckt, bei denen unsere Annahme nicht korrekt war.

Hallo,

den SS-Port habe ich geändert weil der Sketch auch mit dem PIN53 hängen geblieben ist. Da mir nicht so klar war, ob es zwischen dem PIN10 und dem PIN53 SS (Slave Select) beim MEGA Board irgendwelche Wechselwirkungen gibt, habe ich die RF12.cpp auf den PIn49 abgändert. Leider o.E.

Als Library verwende ich die Jeelib Version 2013 (https://github.com/jcw/jeelib)

Mit dem Aubau (siehe Anhang) spielt das Board ohne Problem mit dem PingPong Sketch.
Aslo ist meiner Erachtens der Aufbau OK!?

Gruß
Snoops

Da mir nicht so klar war, ob es zwischen dem PIN10 und dem PIN53 SS (Slave Select) beim MEGA Board irgendwelche Wechselwirkungen gibt, habe ich die RF12.cpp auf den PIn49 abgändert.

Diese Wechselwirkungen gibt es nicht. Ist das die einzige Änderung, die Du an einer der beteiligten Bibliotheken vorgenommen hast?

Ich habe soeben noch ein Problem festgestellt. Der JeeLib-Code benutzt die SPI-Schnittstelle im Interrupt-Handler, der auf den Eingang Pin 2 reagiert. Dort wird vom RFM12B angezeigt, dass er etwas empfangen hat. Wenn sich nun ein solcher Interrupt ereignet, während der normale Programmablauf gerade auf die Ethernet-Hardware (oder allenfalls auf die SD-Karte) zugreift, sind zwei Chips auf dem SPI-Bus aktiv, was fast zwangsläufig zu Problemen führt (eine sog. Race-Condition).
Da nichts in Deinem Code eine solche Race-Condition verhindert, dürfte sie nach nicht allzu langer Betriebszeit mal auftreten.
Nun wirst Du natürlich fragen, wie man das korrigiert. Eigentlich müsste man die JeeLib umschreiben, so dass die SPI-Schnittstelle nicht im Interrupt-Handler benutzt wird, sondern nur ein Flag gesetzt und dann später im normalen Loop die Lese-Aktion durchgeführt. Damit wäre die Lib dann aber für Arduino/Programmier-Anfänger nicht mehr brauchbar, weil eine zeitliche saubere Loop-Aufteilung ohne allzu lange Operationen an einem Stück etwas Programmiererfahrung und Kenntnisse über das Prozessor-Innenleben voraussetzt.

Als (wüste) Alternative wage ich es mal, Dir vorzuschlagen, während jedes Call einer Methode der Ethernet-Bibliothek einfach die Interrupts abzuschalten. Du musst aber schauen, dass das nicht allzu lange geschieht, weil sonst andere Funktionen (unter anderem der RFM12B-Teil) darunter leiden könnten.

Hallo,

ich dachte das SPI Problem hätte ich mit der hier beschriebenen Änderung in der w5100.h Ethernet Lib gefixed.

Sonst habe ich an den beteiligten Libs nichts geändert.

Kann es sein, das es an der RFM12 config liegt? Bei Microcontroller.net http://www.mikrocontroller.net/articles/RFM12 steht folgendes:

RFM hängt sich auf
Wenn man die AFC nicht begrenzt, also keinen Wertebereich vorgibt, die eine maximale Abweichung korrigiert wird passiert es nach einer Weile, dass sich der Empfänger aufhängt, die Offsetbits im Status werden maximal und dann geht gar nichts mehr, er hängt fest.

ich dachte das SPI Problem hätte ich mit der hier beschriebenen Änderung in der w5100.h Ethernet Lib gefixed.

Also noch eine Änderung von der wir bisher nichts wussten…
Aber diese Änderung sollte das Problem auf die beschriebene wüste Art beheben.

Snoops:
Kann es sein, das es an der RFM12 config liegt? Bei Microcontroller.net http://www.mikrocontroller.net/articles/RFM12 steht folgendes:

RFM hängt sich auf
Wenn man die AFC nicht begrenzt, also keinen Wertebereich vorgibt, die eine maximale Abweichung korrigiert wird passiert es nach einer Weile, dass sich der Empfänger aufhängt, die Offsetbits im Status werden maximal und dann geht gar nichts mehr, er hängt fest.

Könnte ich mir gut vorstellen. Wenn ich auf dieser Seite etwas weiter lese, dann scheint es grundsätzlich eine schlechte Idee zu sein, diesen Chip neben anderen Tätigkeiten auf einem Mikrokontroller zu verwenden.
Da bei Dir der PingPong-Sketch aber über längere Zeit zu laufen scheint, dürfte das Problem doch etwas verzwickter sein. Die zeitliche Abfolge scheint bei diesem Chip eng einzuhalten sein, andernfalls er einfach mal zu blockieren gedenkt. Ich würde mal versuchen, das Teil an einen separaten UNO zu hängen, alle Änderungen an den Bibliotheken rückgängig zu machen und den per I2C an den Mega zu hängen. Dann kannst Du notfalls den UNO per digitalen Output vom Mega her resetten, mitsamt dem Radio-Chip daran.

tst

Hatte das Problem auch.

Die Lösung war beim Maga, das ich die Pins 10+53 auf Ausgang und auf LOW setze und Pin 4 auf Ausgang und auf HIGH , wenn ich das Lan nutzen möchte.

Will ich die SD-Karte nutzen Pins 10+53 auf Ausgang und auf HIGH setze und Pin 4 auf Ausgang und auf LOW

Seit dem läuft es.

Bye Carsten