Hallo,
im rätsle im Moment an einem Problem.
Im TWI Interrupt möchte ich (zu Debugzwecken) Daten mit dem UART
ausgeben.
Mache ich das Interrupt gesteuert (Daten in Puffer schreiben und UDRE
aktivieren) Funktioniert mein TWI nicht mehr.
Es scheint als ob ich in eine Endlos Schleife gerate.
Mache ich die UART per "Polling" ist alles bestens.
Vermutlich sehe ich den Wald vor lauter Bäumen nicht mehr.
Genutzt wird auf beiden Seiten ein atmega32.
Die UART und TWI Dateien mal anbei. TWI wird nur im MT oder MR Modus
betrieben !
Hat jemand einen Tipp für mich ?
Danke im voraus
Juergen
Aus einer ISR heraus eine Funktion aufrufen, die selber mit cli() /
sei() rumspielt ist immer ... gefährlich.
Wenn dir der Sendepuffer überläuft, dann hast du hier ein Problem:
1
voiduartPut(charc)
2
{
3
#ifdef UART_TX_DEBUG_MODE
4
#warning "UART_TX_DEBUG_MODE"
5
while(!(UCSRA&_BV(UDRE)))
6
nop();
7
8
UDR=c;
9
10
#else
11
// loop until we have space
12
while(txpos>=(sizeof(txbuffer)-2))
13
{
14
nop();
15
}
tja. da kannst du lange warten. Die Funktion wird aus einer ISR heraus
aufgerufen und zu diesem Zeitpunkt sind Interrupts daher gesperrt. Kein
Interrupt -> kein Ausräumen des Sendepuffers -> Endlosschleife.
Guter Punkt.
Habe den TX Puffer von 20 Zeichen auf 100 vergrößert, trotzdem noch...
Werde mal einen Pin toggeln ind er Schleife, dann weis ich ob es die
Schleife ist.
Das akute Problem ist das sei() in uartPut. Das kommt zur Ausführung
bevor das TWINT-Flag gelöscht wird, ergo steckst du in einer endlosen
TWI-Interrupt Rekursion fest.
PS: Ok, nicht wirklich endlos. Nur bis der Puffer durch die Rekursion
voll ist, dann schlägt das von Karl Heinz erwähnte Problem zu.
Mir ist jetzt klar, was passiert. eine Lösung ohne den Puffer zu
vergrößern sehe ich im Moment nicht.
Danke für den Wink mit dem Zaunpfahl.
Gruss
Juergen
Jürgen Sachs schrieb:> Mir ist jetzt klar, was passiert. eine Lösung ohne den Puffer zu> vergrößern sehe ich im Moment nicht.> Danke für den Wink mit dem Zaunpfahl.
Das klingt jetzt nach einer Binsenweisheit:
In einer ISR gibt es keine lang andauernden Operationen.
Insbesondere gibt es keine Ausgaben auf LCD oder UART. Das alles dauer
viel zu lang. Und wie du gesehen hast, ist auch eine High-Tech Lösung
mit Ausgabe in einem Interrupt keine Lösung. Eine ISR darf/soll nicht
von anderen Interrupts abhängen, sondern muss auf jeden Fall immer
komplett durchlaufen.
Was eine ISR machen kann: Sie kann mit ein paar globalen Variablen
arbeiten und dort bestimmte Werte reinschreiben, die dann in der
Hauptschleife dafür sorgen, dass die Texte ausgegeben werden. Das hat
dann auch den Vorteil, dass die Ausgaben geordnet erfolgen und dir eine
Ausgabe in einer ISR nicht mitten in eine andere Ausgabe in der
Hauptschleife reinplatzt, nur weil der Interrupt zufällig dann gekommen
ist, wenn in der Hauptschleife auch gerade eine Ausgabe läuft.
Ja, das ist mir bewusst.
Aber die Daten muss ich, für eine spätere Bearbeitung, in einen Puffer
schreiben, egal ob in Mainline oder im Interrupt verarbeitet wird.
Ob ich den nun in Mainline oder im Interrupt wieder leere, macht keinen
Unterschied. Auf mein Problem treffe ich immer.
Ist der Puffer voll, wird nichts abgearbeitet, solange ich in der ISR
des TWI stecke.
Später wird natürlich in Mainline das ganze ausgewertet und ein Display
mit Leben gefüllt. Dazu gehören leider auch Variable Texte die daher
über TWI kommen und nicht im Flash des Controllers am Display stecken
können.
Aber diese "RX Puffer voll" Situation bekomme ich wohl immer....
Jürgen Sachs schrieb:> Aber diese "RX Puffer voll" Situation bekomme ich wohl immer....
Jep.
Ist wie im täglichen Leben. Wenn dir der Chef sukzessive mehr Arbeit auf
den Schreibtisch legt als du abarbeiten kannst, dann wird irgendwann der
Schreibtisch voll und du urlaubsreif.
Dann muss man auch mal den Mut haben und eine Übertragung mit einem
Bufferoverrun als gescheitert erklären und die Daten verwerfen, bzw. der
Gegenstelle mitteilen, dass sie sich doch bitte etwas zurückhalten soll.
Wenn Du der I2C-Master bist, hast Du doch alle Zeit der Welt.
Sende einfach das Debugpaket komplett aus dem Puffer raus und erst dann
mach den nächsten I2C-Transfer.
Niemand zwingt Dich, Deine CPU mit haufenweise I2C-Zeugs vollzupumpen.
Der Trick bei effizienter Programmierung ist, mache alles immer nur so
oft, wie nötig.
Peter
Peter Dannegger schrieb:> Wenn Du der I2C-Master bist, hast Du doch alle Zeit der Welt.
Bei den Debugausgaben gebe ich dir (Bedingt) recht. Die sind jetzt auch
eher nur für den Stresstest um genau solche Schwachpunkte auf zu decken.
Das es sich um ein RC Fernbedienung handelt, kann ich natürlich nicht
ewig Pause machen.
In Mainline polle ich die Analog und Digitaleingänge.
Per Interrupt mache ich das Timing (Zeitbasis), UART senden und
Empfangen, TWI senden und Empfangen.
Auch die Auswertung der Befehle die per UART, Digital Input usw ankommen
werden in Mainline verarbeitet.
Dort Erzeuge ich die entsprechenden Daten und sende diese entweder per
UART (Hängt ein BTM222 Funkmodul dran) an den RC Empfänger oder z.B.
auch per TWI an das LCD.
Der Prozessor am LCD übernimmt die Grafischen ausgaben und die
Auswertung der Tastatur, Drehgeber usw. So hoffe ich das Display
"tauschbar" machen zu können.
Alles andere hängt im Hauptprozessor.
Jetzt kann ich die Ausführung nicht "ewig" blockieren.
Beim RC-Empfänger, wo ich über TWI erweitern kann, ist das ganze noch
viel kritischer. Die PWM wird ja per Interrupt erzeugt, aber in der
Syncpause wird alles blockiert, bis die Mainline den Zyklus vorbereitet
hat.
Lange Wartezeiten sind daher nicht drin.
Daher war mein Ansatz, wenn immer Möglich alles nur in Puffer zu
schreiben und dann per Interrupt zu verarbeiten.
Im schlimmsten Fall kann es sein, das eine Aktion am LCD (Menüauswahl,
Setting verändern) ein Datenpacket per TWI an den TX CPU geht, diese per
Funk an den RX weiterleitet und der es wieder per TWI an den Empfänger.
Eine Eventuelle Antwort auch wieder zurück :-)
Der Vorteil, das Modell kann in Echtzeit konfiguriert werden. Auch kann
man so Modelle einfach weiter geben von einem TX zum nächsten, etc....
Jetzt muss ich mir hier eben eine Lösung überlegen.
Bisher dachte ich "Im Sonderfall Puffer voll, warten wir eben". Das
innerhalb eines Interrupts der Puffer nicht mehr leer gemacht wird,
daran habe ich nicht gedacht.
Eine Möglichkeit wäre natürlich in diesem Sonderfall UDR per polling zu
bedinenen. Das will ich jetzt mal nicht umsetzen :-)
Danke für die Hilfe
Juergen