Forum: Mikrocontroller und Digitale Elektronik Gesamter Controller (Atmega324) stürtzt ab, wegen ENC28J60


von C. H. (hedie)


Lesenswert?

Guten Abend

Ich habe hier folgenden Aufbau:

Atmega324 @ 10MHz an dem sich ein ENC28J60 befindet.
Auf dem Mega ist Timer0 im CTC Mode konfiguriert mit einem Teiler von 64
und einem anschliessenden TopValue von 7

Dessen Interrupt wird für 3Phasen Software PWM genutzt.

Nun zum Problem:

1. Szenario, ich lasse den PWM Laufen, habe den ENC initialisiert,
lese jedoch nie den Buffer aus.
-> Die Hardware läuft einwandfrei mehrere Stunden.

2. Szenario: Ich lasse den PWM Laufen lese in meiner main() while() 
schleife den Buffer aus, wenn der Controller halt grad Zeit hat :)

-> PROBLEM! Nach bisher nicht definierbaren Zeitabständen stürzt der 
gesamte Controller ab. Der Code wird nicht mehr ausgeführt. (oder 
zumindest geschieht nichts an den IO's. ob der intern noch was am 
rechnen ist, weiss ich nicht.)
Interessanter weise, funktionieren auch Hardwarefunktionen wie der 
Timer0 Interrupt nicht mehr.



Da dachte ich sogleich, dass sich da der Interrupt in die Quere kommt.

Also

3. Szenario: Interrupt des Timers deaktivieren. und den ENC in der 
main() while() schleife auslesen.

-> Erneut das selbe Problem wie bei Szenario 2.



Ich habe mich als erstes auf die Suche nach while schleifen gemacht, 
welche eventuell nicht beendet werden beim auslesen.
Habe leider keine gefunden. Zumal ein ewiges While nicht erklären würde, 
weshalb auch der Interrupt des PWM's unterbrochen wird.

Der Besagte Codeteil sieht so aus:
1
    while((enc28j60Read(EIR) & EIR_PKTIF))
2
    {
3
      enc28j60PacketReceive(ETH_buffer_SIZE, ETH_buffer);
4
    }

Mommentan verwerfe ich den eingelesene Buffer, da es ja auch ohne 
anschliessende Verarbeitung nicht funktioniert.

Zur info, im buffer steht das korrekte.

Ich kann auch mehrere hundert Pakete erfolgreich übertragen bis der 
controller abstürtzt.

Ehrlich gesagt, weiss ich nicht, welche Informationen ich euch hier zur 
verfügung stellen soll.

Deshalb hoffe ich, das mir hier jemand tipps gibt, oder ihr sagt was ihr 
noch wissen müsst, damit wird den Fehler eingränzen können.


Danke schonmal

von Florzo (Gast)


Lesenswert?

Kommentiere die Zeile 42 doch mal aus, das sollte helfen.

von Bernhard S. (b_spitzer)


Lesenswert?

Claudio Hediger schrieb:
> Ehrlich gesagt, weiss ich nicht, welche Informationen ich euch hier zur
> verfügung stellen soll.
Kommentierten Quellcode...
Vermutung: der Controller stürzt ins Nirvana wegen Stack-Überlauf oder 
Überschreitung von Array-Grenzen. Alternativ könnte natürlich auch die 
Hardware schuld sein. Der ENC braucht etwas viel Strom. Wenn auf deiner 
Platine ein 7805, LM317 oder ähnliches die Spannung für den ENC regelt, 
dann schau mal, wie heiß der Regler wird. Hat der ein vernünftiges 
Kühlblech?
Bekommt der ENC irgendwelche (sinnvollen) IP-Paktet vorgesetzt?

von Peter D. (peda)


Lesenswert?

Claudio Hediger schrieb:
> Der Besagte Codeteil sieht so aus:

Das ist kein Code. Das ist nur eine Ansammlung von unbekannten 
Funktionen und unbekannten Variablen, die nirgends definiert werden.
Damit kann keiner was anfangen.

Code ist etwas, was man ohne Warnungen und Errors compilieren kann.
Wenn man dazu zusätzliche Libs oder Header braucht, dann häng sie an 
(als Zip).
Wir haben keine Lust, Rätsel zu raten, wie was definiert sein könnte.

Peter

von C. H. (hedie)


Angehängte Dateien:

Lesenswert?

Peter Dannegger schrieb:
> Wir haben keine Lust, Rätsel zu raten, wie was definiert sein könnte.

Verstehe ich voll und ganz.

Anbei nun also ein zip mit den entsprechenden C-Files und headern.

Es handelt sich dabei um den Gesamten Stack sowie dem kommunikations 
code (spi) und meiner main()

Hoffe jemand hat eine idee...

Danke euch schonmal.

von Bernhard S. (b_spitzer)


Lesenswert?

1
  cli();
2
  LED_ACT_1;
3
  //_delay_ms(50);
4
  LED_ACT_0;
5
6
  while((enc28j60Read(EIR) & EIR_PKTIF))
7
  {
8
    //uart_puts("Weiteres Paket vorhanden!\n");
9
    process_packet(enc28j60PacketReceive(ETH_buffer_SIZE, ETH_buffer));
10
  }
11
12
  sei();
Dass bei dem Programm "seltsamerweise" keine Timer-Interrupts mehr 
durchkommen, liegt vermutlich schwer daran, dass Du sie mit cli() 
deaktivierst...

von C. H. (hedie)


Lesenswert?

Bernhard Spitzer schrieb:
> cli();
>   LED_ACT_1;
>   //_delay_ms(50);
>   LED_ACT_0;
>
>   while((enc28j60Read(EIR) & EIR_PKTIF))
>   {
>     //uart_puts("Weiteres Paket vorhanden!\n");
>     process_packet(enc28j60PacketReceive(ETH_buffer_SIZE, ETH_buffer));
>   }
>
>   sei();Dass bei dem Programm "seltsamerweise" keine Timer-Interrupts mehr
> durchkommen, liegt vermutlich schwer daran, dass Du sie mit cli()
> deaktivierst...

Ja da hast du recht, das aktuelle Programm welches ich als Zip angehängt 
habe, hat das cli und sei nicht mehr drin...

Ich habe inzwischen einiges herausgefunden.

1.

Ich habe diese CodeZeilen:

1
// read the packet length
2
  len  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
3
  len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
4
5
6
  // read the receive status
7
  rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
8
  rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
9
10
  // limit retrieve length
11
  // (we reduce the MAC-reported length by 4 to remove the CRC)
12
  len = MIN(len, maxlen);
13
14
  // copy the packet from the receive buffer
15
  enc28j60ReadBuffer(len, packet);


Durch diese ersetzt bzw. angepasst
1
// read the packet length
2
  len  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
3
  len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
4
5
  if( len > maxlen)
6
  {
7
    LED_STAT_1;
8
  }
9
  else
10
  {  //Nur auslesen, wenn das Paket klein genug ist!
11
12
  // read the receive status
13
  rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
14
  rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
15
16
  // limit retrieve length
17
  // (we reduce the MAC-reported length by 4 to remove the CRC)
18
  len = MIN(len, maxlen);
19
20
  // copy the packet from the receive buffer
21
  enc28j60ReadBuffer(len, packet);
22
23
  }

Zuvor wurde das Paket ungeachtet dessen Grösse ausgelesen und in den 
256Byte grossen Buffer geladen.

Dies verursachte ziemlich sicher einen Speicherüberlauf.

Durch die hinzugefügte IF abfrage wird dies verhindert.

Ich hoffe damit läuft mein Code stabiler.

Des weiteren,

habe ich beim bearbeiten des paketes nicht darauf geachtet, ob dieses 
überhaupt vorhanden ist also size > 0

da die paket ausleseroutine ein return 0 im fehlerfall hat.

Nun scheint es vorerst mal zu funktionieren..

ich weiss, meine rechtschreibung lässt zu wünschen übrig, aber die 
informationen welche ich euch übermitteln wollte, sind dennoch vorhanden 
;)

von Bernhard S. (b_spitzer)


Lesenswert?

Was meldet denn der Compiler, wieviel RAM insgesamt genutzt wird?

In main() nutzt du (eventuell, weil gerade auskommentiert) die Funktion 
printinbuffer(*buffer,*text, terminate). Die macht keinerlei Prüfungen 
der Bereichsgrenzen und Du rufst die so auf:
1
//printinbuffer(&buffer[UDP_DATA],"Hallo, dies ist ein Test des AVR Boardes :) Es laeuft alles perfekt hehehe",TERMINATE);
UDP_DATA ist definiert als 42 (!!), du ballerst hier über 60 Zeichen 
sinnloses gequassel rein und überschreibst dir das RAM.

Davon abgesehen ist mir der Sinn von TERMINATE bei der Funktion unklar. 
Du kopierst einen (hoffentlich) NULL-Terminierten Text in ein anderes 
Array und lässt dabei evtl. mit TERMINATE=0 das Null-Zeichen am Ende 
weg. Mit dem Ergebnis in buffer[] wieder in die Funktion und Du hast 
eine Endlosschleife... Wenn der Speicher vorher Null-Terminiert war, 
dann sollte er das nach dem "memcopy" auch sein.

von C. H. (hedie)


Lesenswert?

Bernhard Spitzer schrieb:
> Was meldet denn der Compiler, wieviel RAM insgesamt genutzt wird?
>
> In main() nutzt du (eventuell, weil gerade auskommentiert) die Funktion
> printinbuffer(*buffer,*text, terminate). Die macht keinerlei Prüfungen
> der Bereichsgrenzen und Du rufst die so 
auf://printinbuffer(&buffer[UDP_DATA],"Hallo, dies ist ein Test des AVR Boardes :) 
Es laeuft alles perfekt hehehe",TERMINATE);UDP_DATA ist definiert als 42 (!!), du 
ballerst hier über 60 Zeichen
> sinnloses gequassel rein und überschreibst dir das RAM.
>
> Davon abgesehen ist mir der Sinn von TERMINATE bei der Funktion unklar.
> Du kopierst einen (hoffentlich) NULL-Terminierten Text in ein anderes
> Array und lässt dabei evtl. mit TERMINATE=0 das Null-Zeichen am Ende
> weg. Mit dem Ergebnis in buffer[] wieder in die Funktion und Du hast
> eine Endlosschleife... Wenn der Speicher vorher Null-Terminiert war,
> dann sollte er das nach dem "memcopy" auch sein.

Es wird 20% (400 Bytes) Ram genutzt

Diese Funktion nutze ich tatsächlich nicht mehr. Diese war für Versuche.

Aber du hast recht.

Hier die besagte memcpy funktion:
1
/*einfache memcpy*/
2
void printinbuffer(uint8_t *buff,uint8_t *text,uint8_t terminate){
3
  while(*text){
4
    *buff++ = *text++;
5
  }
6
  if(terminate) *buff++ = 0x00;
7
}

Momentan habe ich das problem mit dem ENC offensichtlich gelöst.

Nun gibt es ein Problem mit der PWM Erzeugung

Hier mein RGB Code im Interrupt:
1
unsigned int       uiPWMCounter;
2
volatile unsigned int  uiPWMRed;
3
volatile unsigned int  uiPWMGreen;
4
volatile unsigned int  uiPWMBlue;
5
6
ISR(TIMER0_COMPA_vect)
7
{
8
  if(uiPWMCounter == 0)
9
  {
10
11
    uiPWMCounter = PWM_MAX_VALUE;
12
    RGB_R_0;
13
    RGB_G_0;
14
    RGB_B_0;
15
  }
16
17
  if(uiPWMCounter == uiPWMRed)     RGB_R_1;
18
  if(uiPWMCounter == uiPWMGreen)     RGB_G_1;
19
  if(uiPWMCounter == uiPWMBlue)     RGB_B_1;
20
21
  uiPWMCounter--;
22
23
}

Ich weiss ich weiss, der Code ist nicht performance optimal.
Aber darum gehts jetzt nicht :)

Also wie gesagt, versagt jetzt die PWM-Erzeugung nach ca 1minute oder 
mehr.

Der Variable für blau, wird zu beginn der main() Funktion einmalig ein 
Wert zugewiesen. Dieser Wert ändert sich danach nirgendwo mehr im 
Programm.

Die anderen beiden Werte werden Dynamisch aktualisiert.

Es erlischen jedoch alle 3 Farben.

Man kann danach jedoch die Variablen erneut setzen und dadurch den PWM 
wieder generieren lassen.

Es scheint so, als ob die Variablen entweder grösser 300 sind, da dies 
der Maximal Wert ist, oder aber 0.

Da der blau-Wert jedoch nie verändert wird, erscheint mir dies etwas 
mysteriös.

von C. H. (hedie)


Lesenswert?

Claudio Hediger schrieb:
> Es scheint so, als ob die Variablen entweder grösser 300 sind, da dies
> der Maximal Wert ist, oder aber 0.

Die Variable ist definitiv grösser 300

Doch die frage ist, weshalb diese auf einmal hochgezählt wird.

Es scheint fast so, als ob irgendwas den Speicherbereich überschreiben 
würde.


Ich finde dieses Phänomen sehr merkwürdig und mommentan nicht erklärbar.

Ich habe auch schon alle stellen, wo die PWM Variablen gesetzt werden 
(ausser zu beginn in der main() für die Startwerte) auskommentiert.

Und dennoch werden alle 3 Werte (nacheinander! deutlich sichtbar) nach 
einer nicht definierbaren Zeit auf einen wert grösser 300 gesetzt.

von Bernhard S. (b_spitzer)


Lesenswert?

Gleiches Problem. Irgend eine Funktion überschreibt eifrig fremden 
Speicherplatz. Und wenn dann uiPWMRed, uiPWMGreen und uiPWMBlue genullt 
werden, wird es zappenduster.
Pass halt auf mit Arrays und seltsamen Konstantendefinitionen. Ein 
fehlerfreies Programm ist nicht, wenn es meistens oder für eine lange 
Zeit korrekt läuft.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.