Forum: Mikrocontroller und Digitale Elektronik MCP2515 Buffer Overflow?


von Ralf (Gast)


Lesenswert?

Hallo!
Ich schreibe meine Programme in Basic und habe gerade ein Problem.
Habe eine Platine mit 2x MCP2515, die als Gateway funktioniert.
Der µC läuft mit 16Mhz, MCPs laufen auch mit 16Mhz. SPI 1Mhz.
Can 500kb/s. Ca. 40% ausgelastet.

Habe manchmal das Problem, dass die Firmware sporadisch stehenbleibt. 
Bewusst reproduzieren konnte ich das nicht.
Ich vermute es liegt an meinem Programmablauf.

Ich kann leider kein Quellcode hier posten, deswegen schreibe ich mein 
Ablauf.

µC initialisieren
nicht beschaltete Pins aus Ausgang setzen

Interrupts konfigirieren. INT0 1. MCP2515

1. MCP2515 initialisieren (nur zum Lesen)
2. MCP2515 initialisieren (nur zum Senden)

DO

IF A = 1 then  (Leitung INT0 ist mit dem INT Pin vom MCP2515 verbunden)
Empfangsbuffer erkennen (in welchem Buffer die Nachriegt liegt)

  Wenn die Nachricht im Buffer0 liegt
       Daten Buffer0 auslesen und 1:1 mit dem 2. MCP Senden (Sendebuffer 
0)

  Wenn die Nachricht im Buffer1 liegt
       Daten Buffer1 auslesen und 1:1 mit dem 2. MCP Senden (Sendebuffer 
1)

  Wenn die Nachricht im Buffer0 UND Buffer1 liegt
       Daten Buffer0 auslesen und 1:1 mit dem 2. MCP Senden (Sendebuffer 
0)
       Daten Buffer1 auslesen und 1:1 mit dem 2. MCP Senden (Sendebuffer 
1)

A = 0  (Alles quasi abgearbeitet)
end if

LOOP

INT0:
A = 1  (Wenn Empfangsinterrupt ausgelöst wurde, Variable A auf 1 setzen,
        in DO-LOOP dann weiter verarbeiten)
Return



An sich funktioniert das Programm wie geschmiert.
Kann Stundenlang laufen ohne Probleme.
ABER, ab und zu habe ich sporadische Ausfälle, wo ich Reset drücken 
muss.


Meine Vermutung:
Wenn Nachricht empfangen wurde, wird die Variable A auf 1 gesetzt.
Wenn Alles abgearbeitet wurde, wird die Variable A wieder auf 0 
zurückgesetzt.

ABER, was passiert, wenn mein Programm in der Do-Loop-Schleife gerade 
z.B. die Nachricht verschickt UND gerade eine NEUE NACHRICHT eintrifft, 
wird die Variable A nun wieder auf 1 gesetzt.
Das merke ich ja nicht, und arbeite meine DO-LOOP Schleife zu Ende 
ab,und setze die Variable wieder auf 0 (obwohl eine Neue Nachricht da 
ist).

Die neue Nachricht wird nicht ausgelesen, weil A = 0 ist, und Interrupt 
vom MCP2515 wird auch nicht gelöscht, weil er erst beim Auslesen 
gelöscht wird.




Tja, währen ich den Post geschrieben habe, habe ich mein Problem auch 
erkannt.
Ist plausibel, oder?

Biete um Bestätigung.

Gruß
Ralf

von Thomas H. (Gast)


Lesenswert?

Ich würde A im Int immer um 1 erhöhen und die Schleife in der Main 
solange ausführen wie a>0 ist. A dann natürlich nach jedem Durchlauf 
nicht auf 0 setzen sondern um 1 verringern.

Gruß
Thomas

von Fritz (Gast)


Lesenswert?

Hast du dir auch schon die errata-pdf auf der microchip-seite für den 
MCP2515 angesehen?
Könnte hilfreich sein!

von Christoph H. (Gast)


Lesenswert?

Thomas H. schrieb:
> Ich würde A im Int immer um 1 erhöhen und die Schleife in der Main
> solange ausführen wie a>0 ist. A dann natürlich nach jedem Durchlauf
> nicht auf 0 setzen sondern um 1 verringern.
Falls der µC ein AVR ist, dann sollte die Variable A auf jeden Fall nur 
8bit breit sein und mit volatile deklariert werden. Es kann sonst zu 
Problemen kommen, wenn A im Interrupt-Handler verändert wird.

Gruß Chris

von Ralf (Gast)


Lesenswert?

Habe ich jetzt erst durchgelesen.
Gib mir bitte einen Tip, worauf ich achten muss. Sehe da selber nichts.
Danke

von Thomas H. (Gast)


Lesenswert?

@Christoph H.

Habe da Basic gelesen und ging davon aus das Basic das selbst schon 
berücksichtigt. Kenne nur Bascom und da ist es so ;)

Aber klar kommt auch auf den µC an, könnte ja auch ein PIC sein und da
kenne ich mich mit Basic Dialekten nicht aus.

Gruß
Thomas

von Ralf (Gast)


Lesenswert?

Das Problem ist, ich habe nur einen Versuch.
Ich muss die Platinen bald ausliefern, und die sollen stabil laufen.
Falls ich das später umflashen muss, fallen Kosten an umd die Situation 
an sich ist dann auch schlecht.

Die Idee mit :
>A im Int immer um 1 erhöhen ...nach jedem Durchlauf nicht auf 0 setzen >sondern 
um 1 verringern.
finde ich gut, habe aber etwas Angst, dass es sich wieder etwas 
verhacken kann. Weil es kann u.U. sein, dass ich die falschen Daten 
auslese, weil diese nicht aktuell sind.

Wie wäre es mit:
A nicht am Ende auf 0 setzen, sondern sofort am Anfang:

DO

IF A = 1 then  (Leitung INT0 ist mit dem INT Pin vom MCP2515 verbunden)
A = 0
Empfangsbuffer erkennen (in welchem Buffer die Nachriegt liegt)
...
alles erledigen
...

LOOP

Kann das so stabil laufen?

Es ist nicht so schlimm, wenn eine Nachricht verloren geht.
VIEL schlimmer ist es, wenn die Daten (Bytes) falsch ausgelesen und 
gesendet werden, oder das Programm einfach stehen bleibt.

Danke
Gruß
Ralf

von Thomas H. (Gast)


Lesenswert?

Wenn Nachrichten ruhig verloren gehen können könntest du auch nach

IF A=1 THEN

den Interrupt abschalten und am Ende vor dem

END IF

wieder aktivieren, dann sollte es egal sein wo du A innerhalb der IF 
THEN ... END IF auf 0 setzt.

Gruß
Thomas

von Ralf (Gast)


Lesenswert?

Glaube nicht, dass es funktioniert.
Der Interrupt reagiert auf fallende Flanke.
Wenn ich vor End if Interrupt wieder aktiviere, dann ist der Pin bereits 
auf LOW. So stehe ich immer noch beim alten Problem.

Ich glaube ich mache es doch mit A++ und in der DO-Loop A--.
Kann da etwas schief gehen?

Gruß

von Thomas H. (Gast)


Lesenswert?

Hallo Ralf,

ich würde beides probieren denn wenn der INT Low ist beim wieder 
aktivieren ist das ja kein Flankenwechsel nach Low, erst müsste die 
Leitung ja wieder auf High und dann nach Low wechseln um einen Int 
auszulösen.

Aber wie gesagt könnte beides gehen, einfach probieren.

Um welchen controller handelt es sich denn nun eigentlich?

Gruß
Thomas

von Thomas H. (Gast)


Lesenswert?

Ach ja, A-- nicht in der Loop sondern in der IF THEN ... END IF !

Gruß
Thomas

von Ralf (Gast)


Lesenswert?

Handelt sich um AVR und Bascom.

Werde mal probieren, den Fehler zu reproduzieren, wo ich nun weiß wie es 
zustande kommt.
Kann dann die beiden Varianten ausprobieren und gucken, was hilft.

Danke für die Beteiligung.
Gruß

von Ralf (Gast)


Lesenswert?

>Ach ja, A-- nicht in der Loop sondern in der IF THEN ... END IF !

Ja, logisch, habe das so gemeint ;)
Danke für die Aufmerksamkeit.

von H.Joachim S. (crazyhorse)


Lesenswert?

Interrupt auf fallende Flanke ist ganz schlecht. Setz ihn auf low-level.

von Ralf (Gast)


Lesenswert?

>Interrupt auf fallende Flanke ist ganz schlecht.
Warum?

von Ralf (Gast)


Lesenswert?

>terrupt auf fallende Flanke ist ganz schlecht. Setz ihn auf low-level.

Dann kann ich ja ganz ohne Interrupts arbeiten, oder?
Etwa so:

PinX.x = Input

DO

IF PINx.x = 0 then  (Wenn MCP Int Pin auf LOW ist)
Empfangsbuffer erkennen (in welchem Buffer die Nachriegt liegt)
...
alles erledigen
...

LOOP


Spricht da was gegen?

Danke

von H.Joachim S. (crazyhorse)


Lesenswert?

Nein, nicht drauf verzichten.

Wahrscheinlich ist bei dir folgendes Szenario:
1. Interrupt kommt, du liest den MCP aus. Bevor du alles gelesen hast 
können in der Zwischenzeit aber weitere Interrupts gekommen sein, d.h. 
die Int-Leitung bleibt low, und du bekommst nie wieder eine Flanke.

Also levelgesteuerter Interrupt. Ist noch ein weiterer anhängig, springt 
der MC direkt nach Verlassen der ISR wieder in die ISR und versucht den 
nächsten zu bearbeiten.

von Pit (Gast)


Lesenswert?

Das ist eine Menge Text hier. Was ist mit dem Watchdog?

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.