Forum: Mikrocontroller und Digitale Elektronik MSP430 Interrupt


von Daniel G. (daniel83)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen,

nutzen der Forensuche ergab nicht das gewünschte Ergebnis ;-(
Ich habe ein Problem mit UART Interupts.
Ich habe ein Gerät, welches 2 UARTS verwendet. An der einen 
Schnittstelle kommt ca alle 5 sec. ein Protokoll an und der Wert wird 
gespeichert (UART1)
Die andere Schnittstelle (UART2) dient zur Kommunikation mit dem PC.
Beides funktioniert grundsätzlich auch ganz gut. In Kombination treten 
jedoch sporadisch Fehler auf.

Im Anhang befindet sich die Interuptrutine der 2ten Schnittstelle. Die 
der Ersten sieht im Prinzip genau so aus.

Der Fehler entsteht offensichtlich dann, wenn ein Interrupt von der 
ersten Schnittstelle auftritt, während in der 2ten gerade gearbeitet 
wird. Der Fehler tritt nicht auf, wenn ich den Interrupt in der 
initialisierung der ersten Schnittstelle herausnehme. Die kann dann nur 
leider nicht verwenden...

Verarbeitet wird das Protokoll, sobald 8 Bytes angekommen sind. Dies 
geschieht nicht, wenn der Empfang zu lange dauert, wodurch ich wenn die 
Interrupt Routine der zweiten Schnittstelle nicht korekt zuende 
ausgeführt wird ein Timeout bekomme und dadurch das ergebnis für mich 
unbrauchbar ist.

In meiner persöhnlichen prioritätsliste ist die 2te Schnittstelle 
wichtiger als die erste, da nihct viel passiert, wenn ich hier einen 
Wert übersehe.

Aus dem Grund habe ich versucht alle Interrupts wärend der 
Interrupsroutine auszuschalten ( _DINT() _EINT() ) dies hat jedoch 
keinen effekt gehabt.

Hat jemand eine Idee, was ich ncoh probieren könnte? Ist die einzige 
Lösung UART0 und UART1 zu tauschen und den fehler bei der momentan 1sten 
Schnittstelle machen zu lassen?
Klingt eher nach Workaround als nach Lösung.

Gruß Daniel

von Dorean (Gast)


Lesenswert?

Dein Quelltext ist mega stressig zu lesen!
Wie hast du denn die ganzen Einrückungen hibekommen? :)

Außerdem kann man ja garnicht sehen, wie du die initialisiert hast. 
Woher sind die zwei UARTs? Von zwei verschiedenen 
Kommunikationsschnittstellen oder benutzt du beide von einer 
Schnittstelle?

von Daniel G. (daniel83)


Angehängte Dateien:

Lesenswert?

wo ist denn der Stressig zu lesen? der ist Struktoriert.
Einrücken tue ich mit Tabs ;-)

Ich verwende 2 Schnittstellen, sie sind also auch physikalisch einzeln.
Hier die beiden Initialisierungen.

Ach ja, tauschen der Uarts ist nicht möglich, da sich die beschaltung 
unterscheidet und die Platinenlayouts schon zum Hersteller raus sind.

von Daniel G. (daniel83)


Lesenswert?

Grundsätzlich läuft die Übertragung im Übrigen extrem stabil, ahbe eben 
10000 Übertragungszyklen also etwa 60-80k Protokolle verschickt und 
nicht einen Fehler bekommen, nur dier interrupt ist ein Problem.
Wird dieser nicht initialisieret oder einfach nicht angeschlossen 
funktioniert alles ohne Problem. Diesen in Teilen des Codes 
auszuschalten bringt nichts.
Habe den Interrupt für Schnittstelle1 in dem Interrupt für 
Schnittstelle2 und allem was irgendwie mit übertragung zu tun hat 
deaktiviert. Das Problem bleibt.

IE1 &= ~URXIE0;

Ausgeschaltet habe ich ihn so.

Gruß Daniel

von Daniel G. (daniel83)


Lesenswert?

Ich habe mal ausführungszeiten gemessen.

Leere interrupt routine benötigt ca 5us meine Routine etwa 130us.

Es wird pro Protokoll aber nur eine ausgelöst. Also sagen wir so ich 
kann einen Auschlag messen je 500ms ( ich schalte einen Ausgang ein und 
aus, ein beim eingang in die Funktion und aus beim verlassen) Protokolle 
werden alle 500ms gesendet also ein Interrupt je Protokoll. Es werden 
jedoch alle Zeichen ordentlich empfangen ist das Richtig so?

Verwendeter Controler ist der MSP430F149

von (prx) A. K. (prx)


Lesenswert?

Ein "funktioniert fast immer" Szenario ist typisch für sogenannte "race 
conditions" - Fälle, in denen Operationen durch einen Interrupt 
unterbrochen werden, die nicht unterbrochen werden dürfen. Was nur 
selten geschieht. Dann liegt das Problem aber nicht im 
Interrupt-Handler, sondern im übrigen Code.

von rot händle ohne filter (Gast)


Lesenswert?

Schick ma den ganzen Code!

von Daniel G. (daniel83)


Angehängte Dateien:

Lesenswert?

So, das dürfte in etwa alles sein was von interesse ist und in diesem 
Fall ausgeführt werden kann.

Fast immer heißt im übrigen in etwa 99,3% das macht es sehr nervraubend 
das ganze zu debuggen.

von Daniel G. (daniel83)


Lesenswert?

ich habe jetzt den Code für andere Betriebszustände weg gelassen, in 
diese wird in meinem Fall jedoch nicht gewechselt. Dort gibt es auch 
keine weiteren Interruptfähigen Funktionen.

von rot händle ohne filter (Gast)


Lesenswert?

Schreibst du deine Texte im Editor, oder welches Programm macht diese 
Tabs?

von (prx) A. K. (prx)


Lesenswert?

Ohne das nun im Einzelnen untersucht zu haben: Überleg die mal bei jeder 
Zeile in ubGetMessageUart1, was passiert wenn darin ein Interrupt 
ebendieser UART auftritt.

von Daniel G. (daniel83)


Lesenswert?

Fiese Kombination, ich Programmiere in Crossworks und habe die Schnipsel 
hier fix in Visualstudio zusammen Kopiert, das gibt manchmal komische 
verschiebungen. Die sind in Crossworks nicht so groß in VS auch nicht

von Daniel G. (daniel83)


Lesenswert?

@ A.K. es sollte eigentlich nciht viel passieren. ubUart1Receive[][] 
funktioniert als Ringpuffer. Selbst wenn ich nicht wieder in die 
Funktion zurück springe habe ich unterschiedliche wete für 
ubReadUart1Buf und ubWriteUart1Buf, so dass im schlimmsten Fall 2 mal 
Kopiert werden würde.
Außerdem kann zu diesem Zeitpunkt kein Interupt auftretten, da der 
Kommunikationspartner auf eine Antwort wartet.
Aber wie gesagt selbst wenn wird eigentlich normal weiter verfahren, 
außer ich täusche mich massiv, was natürlich nach einigen Tagen ncihts 
anderes angucken durchaus möglich ist.

von Daniel G. (daniel83)


Lesenswert?

Ich habe die selben Funktionen auf einem System laufen, bei dem nur eine 
UART verwendet wird. hier kommt es NIE zu Fehlern.

"NIE" im Sinne von während meiner Tests also zu 1,5 Mio. abfragen.

von (prx) A. K. (prx)


Lesenswert?

Daniel G. schrieb:

> Außerdem kann zu diesem Zeitpunkt kein Interupt auftretten, da der
> Kommunikationspartner auf eine Antwort wartet.

Du kannst selbstverständlich versuchen, mich davon zu überzeugen, dass 
das Programm eigentlich garantiert funktioniere müsste. Aber wie du oben 
selber schon festgestellt hast... Drum kann es nicht schaden, mal die 
eine oder andere Annahme in Frage zu stellen. Zumal grad diese Annahme 
eine böse Tretmine ist, falls sich später mal was ändert.

So kannst du mal versuchsweise neuralgische Punkte absichern, 
beispielsweise den "Have we a message" Block mit abgeschalteten 
Interrupts durchfahren. Mag vielleicht noch mehr davon geben - jeder 
Code, der die gleichen Variablen wie ein Interrupt-Handler verwendet, 
ist ein potentialler Kandidat.

von Daniel G. (daniel83)


Lesenswert?

Was ich versucht habe, ist dass ich den Inhalt des Interupt Handler für 
UART0 auskommentiert habe. So läuft es Problem frei.
Übertragung über UART1 läuft fehlerfrei mit allen weiteren Interrupts, 
was der von UART1 und ein Timer Interrupt ist.
Sobald ich den Interrupt für UART0 einbinde kommt es gelegentlich zu 
Fehlern. Diesen aus zu schalten mit
E1 &= ~URXIE0;
hat jedoch nciht gebracht. Ich habe ihn ausgeschaltet wärend des 
Interrupts von UART1 und über diesen Bereich
1
            vCheckTelegramTimeout();
2
            ubTelegramState=ubGetMessageUart1();
3
            
4
            
5
            
6
            if (ubSystemState == STATE_SOFTWARE )
7
            {
8
                  if( ubTelegramState==UART_TELEGRAM_IO)
9
                  {
10
                        vSoftwareHandler();
11
                  }
12
            }
also immer wen irgend etwas mit Datenübertragung stattfindet.

von Daniel G. (daniel83)


Lesenswert?

Wie du richtig erkannt hast ist die Abfrage bei "Have we a message" die 
einzige Stelle in der empfangs routine in der eine Variable verwendet 
wird, die auch in dem Interrupt verwedentet wird.
Stelle ich an dieser stelle alle interrupts aus, so haben ich keine 
änderung des Verhaltens.

von (prx) A. K. (prx)


Lesenswert?

Da du bislang nie jenen Code gezeigt hast, der die tatsächlichen 
Probleme enthält, sondern immer nur bestimmte Häppchen, kannst du kaum 
mehr als Allgemeinplätze erwarten.

Du schreibst schon mehrfach, dass das Problem nur auftritt, wenn beide 
UARTs in Betrieb sind, zeigt aber seltsamerweise stets nur Code, der 
eine einzige UART verwendet. Wie stellst du dir das vor? So fehlen auch 
die Variablendeklarationen - zwar klingt das bisher nicht nach den 
üblichen "volatile" Problem, aber diese Strategie des information hiding 
führt einfach nicht weiter. Wenn der Fehler exakt da wäre, wo du ihn 
suchst, hättest du ihn vielleicht schon selbst gefunden.

Wenn das zu gross und zu unhandlich ist, dann reduzier den Kram soweit, 
bis es entweder lesbar oder das Problem bei Eingrenzung verschwunden 
ist.

von Daniel G. (daniel83)


Angehängte Dateien:

Lesenswert?

Ok, dann nochmal beide Uarts Zusammenhängend. UART0 wird nur zum gelesen 
nie gesendet.

habe das ganze noch ein wenig reduziert und hoffentlich alles zusammen 
gepackt was wichtig ist.

Viel mehr wird nicht gemacht, habe nur die Port initialisierung und 
sowas weg gelassen.

von (prx) A. K. (prx)


Lesenswert?

Fehlen natürlich wieder die Variablen. Sorry, ich geb's auf.

von Daniel G. (daniel83)


Lesenswert?

1
static ubyte ubReadUart0Buf = 0;
2
static ubyte ubWriteUart0Buf = 0;  // Which Buffer to write 
3
static ubyte ubUart0Pos = 0;       // Position in the Receive- Buffer
4
ubyte ubDummy=0;
5
static ubyte ubUart0Receive[UART_BUFFER_SIZE][9]; // Uart- Receive- Buffer
1
// *** Local variables
2
static ubyte ubReadUart1Buf = 0;
3
static ubyte ubWriteUart1Buf = 0;  // Which Buffer to write 
4
static ubyte ubUart1Pos = 0;       // Position in the Receive- Buffer
5
static ubyte ubUart1Receive[UART_BUFFER_SIZE][9]; // Uart- Receive- Buffer
6
ubyte ubDummy1=0;

So jetzt nochmal die fehlenden Variablen.

Globale gibts auch noch
1
extern ubyte ubTemp[2];
2
3
extern ubyte ubIndexAnlern;
4
5
extern ubyte ubSystemState;
6
extern uword uwSystemTime;
7
extern uword uwInput;
8
extern uword uwInputShadow;
9
10
extern ubyte ubReceive0[8];
11
extern uword uwUart0TelegramTimeout;
12
extern ubyte ubReceive1[8];
13
extern uword uwUart1TelegramTimeout;
14
extern ubyte ubTelegramState;
15
16
extern TS_RAUMEINHEIT tsRaumeinheiten[5];
17
18
extern ulong ulFlags;
Die sind auch ncoh normal deklariert, aber einmal sollte heir reichen.

die Struktur:
1
// *** Global Structs
2
typedef struct   {
3
                  ubyte ubAdress;               //Busadress
4
                  ubyte ubFlags;
5
                  ubyte ubTemp[2];
6
                  ubyte ubOffset[2];
7
                  ubyte ubReState;
8
                  ubyte ubReStateShadow;
9
                  ubyte ubMinTemp;
10
                  ubyte ubMinTempDiff;
11
                  ubyte ubTimeOpen;
12
                  ubyte ubTimeOpenLeft;
13
                  ubyte ubClock;
14
                  ubyte ubRelais;
15
                  uword ubPulseTime;
16
                  uword uwPulseTimeLeft;
17
                  ubyte ubRetrys;
18
                  } TS_RAUMEINHEIT;

und die wichtigen Konstaten, wo es möglicherweise fehler geben könnte:
1
// * Uart Buffer- Size
2
#define UART_BUFFER_SIZE  5
3
4
// * Uart0 Flags
5
#define BIT_ULFLAGS_UART0_RECEIVING              BIT0
6
#define BIT_ULFLAGS_UART0_ANYTHING_TO_READ       BIT1
7
#define BIT_ULFLAGS_UART0_SENDING                BIT2
8
9
10
// * Uart1 Flags
11
#define BIT_ULFLAGS_UART1_RECEIVING              BIT3
12
#define BIT_ULFLAGS_UART1_ANYTHING_TO_READ       BIT4
13
#define BIT_ULFLAGS_UART1_SENDING                BIT5
14
#define BIT_ULFLAGS_UART1_ANYTHING_TO_DO        BIT6
15
16
// * Telegramm States
17
#define UART_TELEGRAM_IO            0x01
18
#define UART_TELEGRAM_ERROR         0X02
19
#define UART_TELEGRAM_TIMEOUT       0x03

Der Rest sind nur Zahlen oder sind Zimeout Zeiten auch interesant?

von (prx) A. K. (prx)


Lesenswert?

Jedenfalls fehlt volatile.

von Daniel G. (daniel83)


Lesenswert?

@ A.K. es tut mir sehr leid wenn ich dir in meinem bemühen das ganze 
lesbar zu machen vor den Kopf gestoßen habe, das war nie meine Absicht. 
Ich hoffe du nimmst es mir nicht al zu übel. Das Programm ist über 
einige Dateien verteilt. deshalb ahbe ich die Wichtigen Teile zusammen 
kopiert und möglicherweise Teile ausgelassen, die evtl. wichtig sein 
könnten.

von Daniel G. (daniel83)


Lesenswert?

Kurzes Googlen ergab volatile verhindert, das isrgendwo Kopien einer 
Variablen erstellt werden oder diese weg optimiert werden.
Es schadet also nicht, bis auf , dass ich die optimierung meines 
Compilers aushebele.
Ich habe jetzt mal an allem was irgendwie benutzt wird ein volatile 
davor geschrieben. es ändert am verhalten leider nichts.

von Daniel G. (daniel83)


Lesenswert?

Ich denke den "Fehler" gefunden zu haben. Es wird sich wohl um eine 
Timing Problem gehandelt haben. nachdem ich die Checksummen überprüfung 
ausgelagert habe hat sich die Fehler anfälligkeit mindestens drastisch 
reduziert.

Eine frage hätte ich noch. Ich bin im Moment noch unzufrieden mit deisem 
Konstrukt
1
if ( RXBUF1 == AUSSEN_TEMP || RXBUF1 == RE_START_ANLERN
2
               || RXBUF1 == RE_NEW_ADRESS
3
               || RXBUF1 == RE_QUIT_ANLERN
4
               || RXBUF1 == RE_STATUS_MELDEN
5
               || RXBUF1 == RE_STATUS_AENDERN
6
               || RXBUF1 == RE_ERROR_STATE 
7
               || RXBUF1 == SW_GET_TEMP
8
               || RXBUF1 == SW_GET_INPUT
9
               || RXBUF1 == SW_GET_ALLOCATION
10
               || RXBUF1 == SW_GET_PERIODE)

wenn ich daraus eine switch anweisung mache, die immer das gleiche 
macht, gewinne ich dadurch Zeit? im falle von "RXBUF1 == SW_GET_PERIODE" 
muss der Controler ja erst alle anderen abfrage. Da an dieser stelle 
noch einige Möglichkeiten hinzu kommen werden würde hier mit sicherheit 
einige Zeit verloren gehen.
Unsicher bin ich, ob der Compiler aus der switch anweisung intern wieder 
eine geschachtelte Abfrage macht. Hat hier jemand erfahrungswerte und 
möchte die mit mir teilen?

von (prx) A. K. (prx)


Lesenswert?

Wenn RXBUF1 ein I/O-Register ist, dann ist diese Anweisung definitiv 
ineffizient, denn dann wird für jeden einzelnen Vergleich der Port neu 
ausgelesen (weil volatile). RXBUF1 sollte vorneweg einmal in eine lokale 
Variable ausgelesen werden.

Ein Switch-Statement wird wahrscheinlich effizienter sein als solch ein 
Stapel Vergleiche. Meist erzeugt ein Compiler aus einem nicht zu 
winzigen switch Statement je nach Werteverteilung entweder eine Tabelle 
[O(1)] oder einen Vergleichsbaum [O(log N)] an Stelle deiner linearen 
Suche [O(N)]. Ja nach Werteverteilung kannst du auch selbst eine Tabelle 
verwenden.

von (prx) A. K. (prx)


Lesenswert?

PS: Wenn RXBUF1 ein UART-typischer Transferpuffer ist, also einer der 
sich beim Auslesen automatisch leert, dann wundert mich nix mehr.

von Daniel G. (daniel83)


Lesenswert?

Wieso das?

Die variante mit der Switch anweisung bringt leider gar nichts, die 
Zeiten sind identisch mit denen beim benutzen der Schachtel if 
Konstruktion.
Das verwenden eine Variable statt dem RXBUF war jedoch viel 
versprechend. hier gewinne ich 36us bei 192us bzw jetzt 156us eine ganze 
Menge wie ich finde.
Mal sehen was ich noch so an Möglichkeiten finde

von Stefan (Gast)


Lesenswert?

>PS: Wenn RXBUF1 ein UART-typischer Transferpuffer ist, also einer der
>sich beim Auslesen automatisch leert, dann wundert mich nix mehr.
Da leert sich gar nix! Nur das IRQ-Flag (IFG) wird zurückgesetzt.

>hier gewinne ich 36us bei 192us bzw jetzt 156us eine ganze
>Menge wie ich finde.
>Mal sehen was ich noch so an Möglichkeiten finde
Ich sehe keinen driftigen Grund, warum man in der ISR jedes empfangene 
Byte komplett auf alle möglichen Bedingungen hin untersuchen sollte?
Ein Rahmen mit BeginOfFile und EndOfFile-Kennung reicht doch völlig aus. 
Der empfange String wird dann irgendwo in main() auf Gültigkeit und Sinn 
untersucht!

von (prx) A. K. (prx)


Lesenswert?

Stefan schrieb:

>>PS: Wenn RXBUF1 ein UART-typischer Transferpuffer ist, also einer der
>>sich beim Auslesen automatisch leert, dann wundert mich nix mehr.

> Da leert sich gar nix! Nur das IRQ-Flag (IFG) wird zurückgesetzt.

Ok, ob sich der Inhalt ändert oder nicht mag unterschiedlich sein und 
hängt sicherlich auch von der Puffertiefe ab. Vielleicht ist das beim 
MSP430 ja anders, aber üblicherweise werden solche Pufferregister genau 
ein einziges Mal pro empfangenem Byte ausgelesen.

von Daniel G. (daniel83)


Lesenswert?

>Ich sehe keinen driftigen Grund, warum man in der ISR jedes empfangene
>Byte komplett auf alle möglichen Bedingungen hin untersuchen sollte?

Die abfrage wird nur beim ersten Byte eines Potentiellen Protokolls 
durch geführt. Die folgenden Bytes werden nur eingelesen.
Dies hat den Grund, dass ich nciht garantieren kann, dass das erste 
empfangene Byte immer der anfang eines Protokolls ist. Diese Abfrage 
dient dazu, dass der Controler, für den Fall das er den Anfang der 
Protokolle aus irgend einem Grund verliert, wieder bei einem Ersten Byte 
anfängt zu lesen und so wieder in einen normalen empfangszyklus zurück 
kehrt.

von Stefan (Gast)


Lesenswert?

Daniel G. schrieb:
>>Ich sehe keinen driftigen Grund, warum man in der ISR jedes empfangene
>>Byte komplett auf alle möglichen Bedingungen hin untersuchen sollte?
>
> Die abfrage wird nur beim ersten Byte eines Potentiellen Protokolls
> durch geführt. Die folgenden Bytes werden nur eingelesen.
> Dies hat den Grund, dass ich nciht garantieren kann, dass das erste
> empfangene Byte immer der anfang eines Protokolls ist. Diese Abfrage
> dient dazu, dass der Controler, für den Fall das er den Anfang der
> Protokolle aus irgend einem Grund verliert, wieder bei einem Ersten Byte
> anfängt zu lesen und so wieder in einen normalen empfangszyklus zurück
> kehrt.

Deshalb ja auch die Nutzdaten in <BOF> ... <EOF> einschließen.
Dann muss man nur nach BOF und nach EOF suchen ;-)

von Daniel G. (daniel83)


Lesenswert?

>Deshalb ja auch die Nutzdaten in <BOF> ... <EOF> einschließen.
>Dann muss man nur nach BOF und nach EOF suchen ;-)

Ich glaube damit bekomme ich das hin Interupt zeit liegt jetzt bei ca 
104us bis jetzt 48K Protokolle ohne Fehler. Ich werde das heute Nacht 
ncohmal testen. Habe allerdings ein 0xFF verwendet, da dieses Zeichen 
nur unter monströs unwahrscheinlichen Umständen als Checksumme vorkommen 
aknn und das müsste genau dann passieren, wenn gerade ein Fehler 
vorliegt.

Soweit so gut und vorerst Danke für eure Hilfe

von Daniel G. (daniel83)


Lesenswert?

Auch über Nacht gab es keine Fehler, ich denke damit sollte das Problem 
aus der Welt sein, Danke für eure Hilfe

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.