www.mikrocontroller.net

Forum: Compiler & IDEs problem mit peter fleurys uart lib und interrupts


Autor: ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

erstmal danke an Peter Fleury für die wunderbare lib :-)

habe allerdings ein kleines Problem.

wenn ich aus einer Interruptroutine (z.B. Timerinterrupt) heraus 
mehrmals die funktion uart_putc aufrufe und deutlich mehr sende, als die 
Buffergröße hängt sich mein programm auf. Bei einer Buffergröße von 8 
Byte funktioniert es z.B. noch, wenn ich 15 Byte sende, bei 16 Byte ist 
dann schluss. Es ist aber nicht die doppelte Bytezahl bei 64Byte Buffer 
schon bei etwa 70Byte Schluss
//uart TX Buffer = 8
ISR(irgendwas)
{
    for(uchar8 i=0; i<16;i++)
    //for(uchar8 i=0; i<15;i++)  geht noch
    {
  uart_putc(56);
    }
    //Ab hier wird kein Code mehr ausgeführt
}

oder
//uart TX Buffer = 64
ISR(irgendwas)
{
    for(uchar8 i=0; i<70;i++)
    //for(uchar8 i=0; i<64;i++)  geht noch
    {
  uart_putc(56);
    }
    //Ab hier wird kein Code mehr ausgeführt
}

Außerhalb vin Interruptroutinen habe ich das Problem nicht und wenn ich 
den TX Buffer vergrößere tritt es auch nicht auf.

Habe auch obige schleife experimentell mit cli(); sei(); umschlossen um 
auszuschließen, dass mir vielleicht ein anderer Interrupt 
dazwischenfunkt, das Verhalten ist jedoch das selbe.

(und klar, kann ich den Buffer größer machen , die Anzahl der zu 
sendenden Bytes ist aber nicht kostant und kann unter Umständen auch mal 
groß werden.)

Bin Ratlos, danke für Hilfe

Autor: Tom M. (tomm) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Habe auch obige schleife experimentell mit cli(); sei(); umschlossen um
> auszuschließen, dass mir vielleicht ein anderer Interrupt
> dazwischenfunkt, das Verhalten ist jedoch das selbe.

Vermutlich müsstest du's genau andersrum machen: Interrupts freigeben, 
damit der TX Interrupt (USART0_TX_vect o.ä.) ausgeführt wird, damit 
leert sich der Sendepuffer.

Autor: ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Vermutlich müsstest du's genau andersrum machen: Interrupts freigeben,
>damit der TX Interrupt (USART0_TX_vect o.ä.) ausgeführt wird, damit
>leert sich der Sendepuffer.

Das macht eigendlich schon uart_putc:
/* enable UDRE interrupt */
    UART0_CONTROL    |= _BV(UART0_UDRIE);

Autor: Tom M. (tomm) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auf dem AVR hast du aber per Default keine "nested interrupts": Der 
Interrupt Handler für die USART wird deinen Interrupt nicht unterbrechen 
(der blockiert ja, weil der Ringpuffer voll ist).

Autor: ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tatsächlich!

dachte immer die avr interrups wären per default nested, aber hier steht 
das gegenteil: 
http://www.nongnu.org/avr-libc/user-manual/group__...

wieder was gelernt..

werde es mal ausprobieren, danke. Habe leider gerade meinen avr 
"programmiert" ohne die Betriebsspannung anzuhängen und seitdem reagiert 
er nicht mehr. Muss also bis Montag warten....:-(

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dass in einer ISR die Interrupts per Default deaktiviert sind, ist genau 
das Problem hier. Die Fleury-Lib versendet die Zeichen aus dem Puffer 
per Interrupt. Wird uart_putc aufgerufen während der Puffer voll ist, 
wartet die Funktion so lange, bis wieder Platz im Puffer ist. Da aber 
die Interrupts gerade deaktiviert sind, wird nichts gesendet, also wird 
auch kein Platz im Puffer frei, also wird bis in alle Ewigkeit gewartet.

Autor: ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine Frage hierzu:

ich möchte nun also erreichen, dass mein Interrupt vom USART_UDRE_vect 
unterbrochen werden kannauf keinen Fall aber von anderern Interrupts.

Das einzige, was mir dazu einfällt ist es
(1) die Register der in Frage kommenden Interrupts zu sichern (also z.B. 
TIMSK1, UCSR0B, usw...)
(2) in diesen nun alle Interrupts bis auf den DataRegisterEmpty 
Interrupt zu deaktivieren,
(3) sei(),
(4) meine Zeichen zu senden,
(5) cli()
(6) und dann alle Register rücksichern.

Hat jemand ne Idee, wie das einfacher gehen könnte?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn irgendwie möglich, solltest du zu Plan B überwechseln:
In der ISR gar nicht ausgeben. Zumindest nicht derartige Mengen.

Setzt dir in der ISR ein Jobflag und atbeite das im Hauptprogramm ab und 
mach von dort die Ausgaben.

In einer ISR möchtest du normalerweise sowieso nicht ausgeben, da dir 
dieser Interrupt jederzeit überall reinknallen kann, zb auch dann, wenn 
im Hauptprogramm gerade eine Stringausgabe läuft.
Das was du in der ISR ausgibst, taucht dann mitten in der Stringausgabe 
aus. Sind in der Stringausgabe (die den Buffer befüllt) Interrupts nicht 
sowieso gesperrt, dann kann es sogar sein, dass du in mächtige Probleme 
reinläufst, weil die Funktion höchstwahrscheinlich nicht reentrant 
geschrieben ist.

Autor: ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke, werde ich mir zu Herzen nehmen, sende die Zeichen in der 
Interruptroutine, da ich sie sehr timinggenau ausgeben möchte, aber 
werde mal testen, ob es auch noch genau genug ist, wenn ich sie in der 
main schreibe...

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>ich möchte nun also erreichen, dass mein Interrupt vom USART_UDRE_vect
>unterbrochen werden kannauf keinen Fall aber von anderern Interrupts.
>
>Das einzige, was mir dazu einfällt ist es
>(1) die Register der in Frage kommenden Interrupts zu sichern (also z.B.
>TIMSK1, UCSR0B, usw...)
>(2) in diesen nun alle Interrupts bis auf den DataRegisterEmpty
>Interrupt zu deaktivieren,
>(3) sei(),
>(4) meine Zeichen zu senden,
>(5) cli()
>(6) und dann alle Register rücksichern.
>
>Hat jemand ne Idee, wie das einfacher gehen könnte?

>Hat jemand ne Idee, wie das einfacher gehen könnte?

*Das hier reicht völlig:*

(1) sei(),
(2) meine Zeichen zu senden,
(3) cli()

An den anderen Registern und Bits must Du nix fummeln, darum kümmert 
sich der Compiler und die CPU drum.

Aber ich muss Karl rechtgeben, in einer ISR solltest Du keine Ausgaben 
machen. Falls es doch nötig ist, dann sowenig wie möglich (z.B. 1..3 
Zeichen)

Autor: ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>An den anderen Registern und Bits must Du nix fummeln, darum kümmert
>sich der Compiler und die CPU drum.


Ach und woher weiß der compiler, dass ich gerne vom DataRegisterEmpty 
Interrupt unterbrochen werden will, aber sonst von keinem anderen 
Interrupt?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ben schrieb:
>>An den anderen Registern und Bits must Du nix fummeln, darum kümmert
>>sich der Compiler und die CPU drum.
>
>
> Ach und woher weiß der compiler, dass ich gerne vom DataRegisterEmpty
> Interrupt unterbrochen werden will, aber sonst von keinem anderen
> Interrupt?

Der Compler weiß es nicht und der µC auch nicht.

Die von Peter vorgeschlagene Methode birgt die Gefahr, daß dir alles um 
die Ohren fliegt, zB wenn die irgendwas-ISR von sich selbst unterbrochen 
wird weil die Ausgabe zu lange dauert. Dort wird sie dann wieder von 
sich selbst unterbrochen etc, bis der Stack ausgeht und der µC (bzw. das 
Programm) dann ziemlichen Unsinn treibt und schliesslich nicht 
unwahrscheinlich im Reset landet.

Timing-ganu kannst du hier schlecht sein, weil die Ausgabe durch die 
UART-ISRs erledigt wird, und deren Aufrufverhalten ist abhängig von der 
Baudrate und zudem von der IRQ-Latenz. Letzteres hast du ja schon 
schmerzlich festgestellt...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.