Forum: Mikrocontroller und Digitale Elektronik sporadische Fehler mit Interrupt


von Rafi D. (alexanderw)


Angehängte Dateien:

Lesenswert?

Hallo,

in dem angehängten Code konnte ich den Fehler soweit eingrenzen sodass 
ich sehen konnte das nicht immer die Variable TelegrammReady gesetzt 
wird.
Zu 80% gehts gut, die Variable wird gesetzt und in der main routine wird 
dann mit der entsprechenden if-Abfrage (if (TelegrammReady==true)) der 
Code abgearbeitet.
Aber wie gesagt sporadisch.
In der main ist TelegrammReady global als
extern volatile bool TelegrammReady
definiert.

Wie kann das sein das er manchmal im Code die Zeile üebrspringt wo 
TelegrammReady gesetzt wird?
Alle anderen Zeilen werden abgearbeitet und ich sehe dann auch das das 
Startbit erkannt wurde und die genaue Anzahl an Bytes gelesen wurde.
Ein atomarer Zugriff wäre nicht möglich da in der ISR per UART Daten 
gesendet und die UART ist nach Fleury.

Könnte ich einen Denkanstoss kriegen? Ich hänge gerade hier fest und 
weiß nicht woran e liegen könnte.

von Rainer B. (katastrophenheinz)


Lesenswert?

Hi,

in welchem Zeitlichen Abstand kommen die Bits an und wie lang ist worst 
case die durchlaufzeit der ISR?

gibt es neben deiner INT2-Routine noch weitere, zeitfressende 
ISR-Routinen ( die der Uart-Lib ausgenommen ) ?

von Linksammler (Gast)


Lesenswert?

Rafi Dafi schrieb:
> da in der ISR per UART Daten

Das ist ungünstig.
die UART-Lib braucht beim Senden zwingend aktive Interrupts (sobald der 
Buffer voll ist), aber innerhalb der ISR sind diese per Default 
deaktiviert.

bevor du nun mit cli/sei innerhalb deiner ISR hantierst:

Versuch mal höhere Baudrate, kürzere Texte oder größeren Buffer für den 
UART.

die "Saubere" Lösung wäre jedoch, alle uart-sachen aus der ISR 
rauszuhalten.

von Rafi D. (alexanderw)


Lesenswert?

Die UART bzw. die ISR für die UART ist nicht das Problem.
HAbe schon in die ISR(INT2_vect)
uint8_t sreg = SREG;
cli();
....
SREG = sreg;
eingepflegt um den zugriff anderer ISR's zu verhindern, aber kein 
Erfolg.
Ich reiss mir hier noch die HAare raus.

von Rafi D. (alexanderw)


Lesenswert?

Es ist auch egal in welchem Abstand ich so ein Frame schicke bzw. 
empfange. Jede sekunde oder jede 100ms.

Rainer B. schrieb:
> in welchem Zeitlichen Abstand kommen die Bits an und wie lang ist worst
> case die durchlaufzeit der ISR?

wie kann ich diese Durchlaufzeit berechnen? Müsste ich nicht dazu die 
Assembler befehle auswerten?

Rainer B. schrieb:
> Hi,
>
> in welchem Zeitlichen Abstand kommen die Bits an und wie lang ist worst
> case die durchlaufzeit der ISR?
>
> gibt es neben deiner INT2-Routine noch weitere, zeitfressende
> ISR-Routinen ( die der Uart-Lib ausgenommen ) ?

Ja noch einen Timer OVF ISR

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rafi Dafi schrieb:
> Die UART bzw. die ISR für die UART ist nicht das Problem.

Die uart_puts() in der ISR sind sicher ein Problem. Da schreibst Du 
ganze Strings raus, die einiges an Wartezeit verpulvern, bevor es in der 
ISR selbst weitergehen kann. So etwas macht man anders:

  - Datenspeicherung in der ISR
  - Datenverarbeitung außerhalb der ISR

Zur Kommunkikation zwischen Hauptprogramm und ISR dient ein simples 
Flag, das volatile zu deklarieren ist.

> HAbe schon in die ISR(INT2_vect)
> uint8_t sreg = SREG;
> cli();
> ....
> SREG = sreg;
> eingepflegt um den zugriff anderer ISR's zu verhindern, aber kein
> Erfolg.

Witzig. Wusstest Du eigentlich, dass bei Betreten einer ISR() 
automatisch sämtliche Interrupts deaktiviert und bei Verlassen wieder 
aktiviert werden? Deine Versuche sind daher unsinnig und gleichen einem 
Stochern im Nebel.

> Ich reiss mir hier noch die HAare raus.

Es gibt hier keinen Grund zur Selbstverstümmelung.

von Rafi D. (alexanderw)


Lesenswert?

ICh glaub ich hab den Wurm.
Der Code funktioniert richtig, ich glaub ich hab die falsche Abfrage auf 
das Ende des frames.
Aber danke für die Anstösse, werde berichten wenn ich es raus habe.

von Dieter F. (Gast)


Lesenswert?

Was genau fragst Du damit eigentlich ab?

(!(PIND & (1<<PD4)))

Das es eine PIN-Abfrage ist weiß ich - welcher Sinn steckt dahinter?

von Falk B. (falk)


Lesenswert?

@ Rafi Dafi (alexanderw)

>in dem angehängten Code konnte ich den Fehler soweit eingrenzen sodass
>ich sehen konnte das nicht immer die Variable TelegrammReady gesetzt
>wird.

Die Einrückung deines Codes ist schlecht, damit ist er schlecht lesbar.

>Zu 80% gehts gut, die Variable wird gesetzt und in der main routine wird

das ist für ein digitales System keine gute Quote ;-)

>Wie kann das sein das er manchmal im Code die Zeile üebrspringt wo
>TelegrammReady gesetzt wird?

Macht er nicht.

>Ein atomarer Zugriff wäre nicht möglich da in der ISR per UART Daten
>gesendet und die UART ist nach Fleury.

Welche ISR? Ahh, ich sehe es. Hmm, könnte ein Problem sein, wenn die 
Pulsbreiten zu schmal werden und damit die ISR zu langsam. Vorteil ist, 
dass die Funktion uart0_puts() die Daten NICHT direkt sendet sondern in 
den FIFO vom Peter Fleury reinschreibt. Von dort werden die Daten per 
ISR gesendet. Aber das heißt im Zweifelsfall auch, dass die Abarbeitung 
deiner INT2 ISR von der UART ISR verzögert werden kann. Wenn die Pulse 
zu schmal sind, geht die Dekodierung schief.

>Könnte ich einen Denkanstoss kriegen? Ich hänge gerade hier fest und
>weiß nicht woran e liegen könnte.

Ich vermute mal, dass dein Algorithmus für deine Protokollerkennung sich 
verschluckt. Entweder, weil es zu fehleranfällig ist, falsch ist oder 
das Signal nicht sauber ankommt.

Wie schnell klommen denn die Bits bei dem Datenstrom? Minimale 
Pulsbreite?

von Falk B. (falk)


Lesenswert?

@ Dieter Frohnapfel (jim_quakenbush)

>Was genau fragst Du damit eigentlich ab?

>(!(PIND & (1<<PD4)))

>Das es eine PIN-Abfrage ist weiß ich - welcher Sinn steckt dahinter?

Er will den Datenstrom dekodieren. PD4 ist hier garantiert das INT2 Pin.

von Falk B. (falk)


Lesenswert?

if (PIND & (1<<PD4))

Diese Abfrag ist ja mehrfach im Code vorhanden. Also sollte man sie 
sinnvollerweise nur einmal machen, nämlich am Anfang der Routine.

uint8_t data = PIND & (1<<PD4);

...

if (data) ....
if (!data) ...

Das macht den Code nicht nur lesbarer, es verbessert auch das Timing. 
Denn du willst ja rauskriege

von Rainer B. (katastrophenheinz)


Lesenswert?

> uint8_t data = PIND & (1<<PD4);
>
> if (data) ....
> if (!data) ...
>
> Das macht den Code nicht nur lesbarer, es verbessert auch das Timing.
> Denn du willst ja rauskriege

Nee, genau nicht. Denn PIND liegt im unteren IO-Bereich, dh. direkt mit 
SBIC, SBIS abzufragen. Geht deutlich schneller als aus temp. Variablen.
Einziger Nachteil ist der, dass PIND sich während der Ausführung ändern 
könnte. Aber damit kommen wir jetzt bereits in den Bereich der 
Erbsenzählerei.

von Nosnibor (Gast)


Lesenswert?

Rainer B. schrieb:
> Nee, genau nicht. Denn PIND liegt im unteren IO-Bereich, dh. direkt mit
> SBIC, SBIS abzufragen. Geht deutlich schneller als aus temp. Variablen.
> Einziger Nachteil ist der, dass PIND sich während der Ausführung ändern
> könnte. Aber damit kommen wir jetzt bereits in den Bereich der
> Erbsenzählerei.

Das ist aber eine Erbse, an der man sich übel verschlucken kann, wenn 
man sie nicht rechtzeitig zählt!

Wenn ich in der Programmlogik an mehreren Stellen denselben Eingangswert 
brauche, dann muß ich dafür sorgen, daß ich auch jedesmal denselben Wert 
verwende. Und das geht mit einer lokalen Variablen.

Natürlich ist die Wahrscheinlichkeit gering, daß sich der Eingang 
zufällig in diesen paar µs ändert, aber das bedeutet nur, daß dem 
Entwickler der Fehler beim Testen nicht auffällt. In der Praxis 
synchronisiert sich dann irgendwo etwas, und aus "zufällig" wird auf 
einmal "regelmäßig", und dann ist der Fehler schwer zu finden, weil man 
nicht damit rechnet.

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.