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
1
//uart TX Buffer = 8
2
ISR(irgendwas)
3
{
4
for(uchar8 i=0; i<16;i++)
5
//for(uchar8 i=0; i<15;i++) geht noch
6
{
7
uart_putc(56);
8
}
9
//Ab hier wird kein Code mehr ausgeführt
10
}
oder
1
//uart TX Buffer = 64
2
ISR(irgendwas)
3
{
4
for(uchar8 i=0; i<70;i++)
5
//for(uchar8 i=0; i<64;i++) geht noch
6
{
7
uart_putc(56);
8
}
9
//Ab hier wird kein Code mehr ausgeführt
10
}
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
> 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.
>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:
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).
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__avr__interrupts.html
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....:-(
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.
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?
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.
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...
>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)
>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?
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...