Hallo,
ich versuche mich gerade an einer Interrupt-gesteuerten USARt Ausgabe.
Das kleine testprogramm findet ihr im Anhang.
Problem ist, dass ich keine Ausgabe bekomme. Die Ausgabe wird in einen
Ringpuffer zwischengespeichert. In der Funktion, die genau dies tut,
habe ich zum "Test" 3 verschiedene LEDs angesteuert. Problem ist nur,
dass die dritte LED (LED2) dunkel bleibt. Daher sieht es für mich so
aus, als ob das Programm beim hochzählen des Pufferindex hängen bleibt.
Ich kann mir kaum vorstellen, dass da Hochzählen ein Problem darstellt,
aber eventuell findet ihr eine Lösung. Eine Ausgabe bekomme ich
natürlich auch nicht.
Das Programm ist für einen AT32UC3A0512-UES, welcher auf einem EVK1100
verbaut ist. AVR32Studio und die AVR32-Toolchain habe ich erst vor ein
paar Wochen geladen. Sollten also aktuell sein.
~Tobi
Hi,
schon gelöst???
Wenn nein dann sieh dir nochmal deine SendeFunktion "puts" an!!!
Du bekommst keinen Output, wie kann das Sein???
Richtig, du hast vergessen die Daten auszugeben.
Hilfe:
1) Du bekommst nur einen "Tx Empty Int" wenn vorher was gesendet wurde.
jetzt solltest du etwas sehen im Terminal-Prog.
2) was passiert wenn du einen String grösser 128 Zeichen senden
möchtest?
Es wird bei dir nur bis zur Buffer-Size Länge gesendet. :-(
Hier nochmal das Konzept prüfen!
Frage:
Was bedeutet diese Zeile?
Du benutzt Sie an 2 Stellen, die aber beider vom "Ablauf" her
verschieden sind. In der "puts"-Funktion sollte das ein aktivieren des
"Ints" sein und bei der "Tx Empty Int"-Funktion ein deaktivieren???
Da passt was nicht! Oder? Kenn mich mit den AVR32 nicht aus!
LED:
Da kann ich dir leider nicht helfen, sollte so gehen. Was mir aber
auffällt ist das es keine eigene Init für die LEDs gibt, kann da was
nicht stimmen???
mfg
Stephan
Ich bin zwar nicht er AVR - Crack....
... ich glaube aber zu wissen wozu diese TX_EMPTY_MASK gut ist.
Zum einen ist es sicherlich das Interupt - Enable für den UART.
Aber es kann auch in einem weiteren Sinne geutzt werden.
Es gibt ein Problem mit der Initialisierung des UARTS.
Man weiss im Moment wenn man Daten an die Senderoutine übergibt nicht ob
der UART derzeit noch sendet (und damit ein weiterer TX_EMPTY -
Interrupt kommen wird) oder der UART bereits sein Pulver verschossen hat
und der letzte Interrupt schon da war, und fand dass keine weiteren
Daten su senden waren. In diesem Fall muss die Senderoutine den UART
interrupt setzen, damit die ISR aktiv wird. Dies kann man sicher an der
Maske festmachen. Als letzte Aktion in der ISR für diesen Fall muß also
das Flag beeinflusst werden.
letzte Aktion in ISR (im Fall - "keine weiteren Daten"):
Stephan schrieb:> Richtig, du hast vergessen die Daten auszugeben.
Dachte das wird in der ISR gemacht.
Stephan schrieb:> 1) Du bekommst nur einen "Tx Empty Int" wenn vorher was gesendet wurde.
Ich dachte, dafür sei der "TX Ready Int" und für den "TX Empty Int"
bräuchte vorher nichts gesendet zu werden. Jedenfalls war das so bei den
8 Bittern.
Stephan schrieb:> 2) was passiert wenn du einen String grösser 128 Zeichen senden> möchtest?> Es wird bei dir nur bis zur Buffer-Size Länge gesendet. :-(> Hier nochmal das Konzept prüfen!
Was wäre denn ein sinnvolleres Konzept als so viel zu senden wie man
kann? Wenn ich dort warten würde bis wirklich alles gesendet wäre, dann
würd ich wieder eine nicht vorhersagbare Zeit für eine Ausgabe
benötigen. Aber darum geht es ja auch garnicht.
Stephan schrieb:> Frage:> Was bedeutet diese Zeile?(&AVR32_USART0)->ier = AVR32_USART_IER_TXEMPTY_MASK;> Du benutzt Sie an 2 Stellen, die aber beider vom "Ablauf" her> verschieden sind. In der "puts"-Funktion sollte das ein aktivieren des> "Ints" sein und bei der "Tx Empty Int"-Funktion ein deaktivieren???> Da passt was nicht! Oder? Kenn mich mit den AVR32 nicht aus!
In der "puts" verwende ich "&AVR32_USART0)->ier =
AVR32_USART_IER_TXEMPTY_MASK;" zum aktivieren (ier = interrupt enable
register) des "TX Empty Int" und in der ISR, sofern nichts mehr zum
Senden vorliegt, verwende ich "(&AVR32_USART0)->idr =
AVR32_USART_IER_TXEMPTY_MASK;" zum deaktivieren (idr = interrupt disable
register) des selben Interrupts.
Dies entspricht im grunde genau der Routine, wie ich sie auf 8 Bittern
von Atmel erfolgreich verwende.
Stephan schrieb:> LED:> Da kann ich dir leider nicht helfen, sollte so gehen. Was mir aber> auffällt ist das es keine eigene Init für die LEDs gibt, kann da was> nicht stimmen???
Es funktioniert ohne Probleme ohne extra Initialisierung. Daher finde
ich es auch so seltsam, dass LED2 nicht angeht, die anderen beiden aber
schon. Anscheinend wird also die Codestelle mit "LED_On(LED2)" garnicht
erst erreicht und das macht für mich einfach keinen Sinn.
@ THaala
Ich verstehe nicht ganz was du meinst. ALs letzte aktion der
Sendefunktion aktiviere ich den Interrupt. Daher ist es doch im Grunde
irrelevant ob zu dem Zeitpuntk schon alles gesendet ist oder nicht. Wenn
noch etwas zu senden da ist, dann sollte die ISR das ganz normal
raussenden. Wenn nichts mehr da ist, dann wird die ISR den Interrupt
einfach wieder deaktivieren.
dann ist das ok.
>Es funktioniert ohne Probleme ohne extra Initialisierung. Daher finde>ich es auch so seltsam, dass LED2 nicht angeht, die anderen beiden aber>schon. Anscheinend wird also die Codestelle mit "LED_On(LED2)" garnicht>erst erreicht und das macht für mich einfach keinen Sinn.
Vielleicht das DEFINE für LED2 nicht richtig? Richtiger PIN am MC???
>Ich dachte, dafür sei der "TX Ready Int" und für den "TX Empty Int">bräuchte vorher nichts gesendet zu werden. Jedenfalls war das so bei den>8 Bittern.
Das glaube ich nicht, denn ein Interrupt tritt erst nach einer Aktion
auf und nicht einfach so. ;-)
"TX Empty Int"
Das Datenregister zum Senden ist leer.
"TX Ready Int"
Das gesendete Byte ist raus.
Hinweis aus den ATMEGA32 Datenblatt:
TXC: USART Transmit Complete -> "TX Ready Int"
This flag bit is set when the entire frame in the transmit Shift
Register has been shifted out and
there are no new data currently present in the transmit buffer (UDR).
The TXC Flag bit is automatically
cleared when a transmit complete interrupt is executed, or it can be
cleared by writing
a one to its bit location. The TXC Flag can generate a Transmit Complete
interrupt (see description
of the TXCIE bit).
und
UDRE: USART Data Register Empty -> "TX Empty Int"
The UDRE Flag indicates if the transmit buffer (UDR) is ready to receive
new data. If UDRE is
one, the buffer is empty, and therefore ready to be written. The UDRE
Flag can generate a Data
Register empty Interrupt (see description of the UDRIE bit).
Versuchmal das mit dem Schreiben des ersten Zeichen (Byte) zu
machen("put-Funktion", ob sich dann was im Terminal-Prog tut.
mfg
Stephan
PS: Wenn möglich zeigmal den Code den du versuchst nach zu bauen.
Stephan schrieb:> Vielleicht das DEFINE für LED2 nicht richtig? Richtiger PIN am MC???LEDs ein- und ausschalten mittels mitgelieferter Funktionen und Defines
funktioniert. Nur an dieser Stelle halt nicht und daher geht ich davon
aus, dass die Codestelle nicht erreicht wird.
Stephan schrieb:> Das glaube ich nicht, denn ein Interrupt tritt erst nach einer Aktion> auf und nicht einfach so. ;-)
Laut deinem Auszug aus dem ATmega32 Datenblatt kommt der Interrupt aber
"einfach so", was sich auch mit meinen Erfahrungen auf den 8 Bittern
deckt. Wenn das UDR leer ist, dann gibts nen Interrupt.
Ich werden trotzdem mal das erste Zeichen direkt in der Routine
ausgeben, aber ich bezweifel, dass es die Lösung ist. Ich kanns
wahrscheinlich auch erst morgen testen, da ich das EVK1100 nicht zu
Hause habe.
Hi,
lass dir doch mit der normalen "puts"-Funktion Statusinformationen
ausgeben.
Ich hoffe das die funktioniert.
Dann kannst du das Problem mit den Ints und der LED besser untersuchen.
( alle wichtigen Int-Register und das Output-Register für den LED-Port)
mfg
Stephan
Hallo,
-- @ THaala
-- Ich verstehe nicht ganz was du meinst. ALs letzte aktion der
-- Sendefunktion aktiviere ich den Interrupt. Daher ist es doch im
Grunde
-- irrelevant ob zu dem Zeitpuntk schon alles gesendet ist oder nicht.
Wenn
-- noch etwas zu senden da ist, dann sollte die ISR das ganz normal
-- raussenden. Wenn nichts mehr da ist, dann wird die ISR den Interrupt
-- einfach wieder deaktivieren.
"ier" steht typischwerweise für "Interrupt enable register" das heisst
nicht unbedingt dass bei dem Setzen des Enable der Interrupt auch gleich
"anzieht"! Kann sein muss aber nicht - wenn nicht - musst du in dir
selbst seten. Aber eben nur dann wenn der UART nicht mehr akiv ist.
Wenn der UART noch im shiften ist und du setzt den Interrupt wann immer
du gerade lustig bist, wird ein neues Byte in den UART geschriebn - auch
wenn der gar nicht dazu bereit ist - daher ist es keinesweg irrelevant
wann und ob man den Interrupt setzt.
Gruß,
Thaala
P.S. Auch ich habe übserehen das es zwei verschiedene (ier,idr) Aufrufe
waren.....
@ THaala
Aber es wird doch lediglich der Interrupt aktiviert. Es wird also
gesagt, dass es ab jetzt möglich ist, das ein solcher Interrupt
auftritt. Wenn ich an dieser Stelle per Hand einen Interrupt auslösen
würde, dann würde ich deine Argumentation verstehen.
Im Grunde sage ich am Ende der "puts" nur, dass beim nächsten mal, wenn
das UDR leer ist, ein Interrupt ausgelöst werden soll. Und genau das
will ich doch, da die entsprechende ISR sich dann um die Ausgabe
kümmert.
Folgender Code funktioniert auf einem ATmega32 bislang fehlerfrei.
1
voidusart_puts(charconst*str)
2
{
3
while(*str&&(countTX<TX_BUFFER_SIZE)){
4
buffer_out[writer_out]=*str++;
5
countTX++;
6
next_index(writer_out,TX_BUFFER_SIZE);
7
}
8
9
UCSRB|=(1<<UDRIE);// UART Data Register Empty Interrupt enable
10
}
11
12
// Transmit
13
ISR(USART_UDRE_vect)
14
{
15
if(!countTX){
16
UCSRB&=~(1<<UDRIE);// UART Data Register Empty Interrupt disable
Hallo Tobi,
--@ THaala
--Im Grunde sage ich am Ende der "puts" nur, dass beim nächsten mal,
wenn
--das UDR leer ist, ein Interrupt ausgelöst werden soll. Und genau das
--will ich doch, da die entsprechende ISR sich dann um die Ausgabe
--kümmert.
Hast Recht,
Problem ist nur, dass die ISR einmal mehr ausgeführt wird als du Bytes
hast. Letzer Aufruf sagt : Es ist nichts mehr da.
Wenn das Interrupt - Handling Flankengetriggert arbeitet und die
Durchführung der ISR den Interrupt löscht (was ich nicht genau weiß,
bitte selbst nachlesen) dann bekommst Du unter Umständen eben keinen
Interrupt mehr wenn du den Interrupt nur enablest.
Die ISR wurde bereits durchgeführt und der anstehende Interrupt
gelöscht.
Ein erneutes enable bringt dann nichts.
Im Grunde zeigen Stephan's posts in die gleiche Richtung. Nur das er es
unter diesen umständen vorziehen würde das erste byte nicht durch die
ISR in den UART zu werfen sondern direkt über putchar.
Bei der Routine die du zeigst handelt es sich um einen anderen
Interrupt...
Du musst einfach nur herausfinden unter welchen Umständen der TX_EMPTY
Interrupt ansteht. Wenn der TX_EMPTY nach Abarbeitung der ISR weiterhin
ansteht und durch ein disable/enable die ISR erneut ausgeführt wird,
will ich nichts gesagt haben.
Stellt sich noch die Frage wann eigentlich der Interrupt gelöscht wird.
Wenn der auch nach deinem Aussprung aus deiner ISR noch ansteht (will
sagen Du musst den evtl. noch löschen - oder es steht ein anderer
freigegbener Iterrupt an, den du eben nicht löschst in dieser ISR) wäre
das auch eine Erklärung dafür, das deine LED nicht leuchtet. Die ISR
wird einfach dauernd ausgeführt...
Gruß,
Thaala
THaala schrieb:> Stellt sich noch die Frage wann eigentlich der Interrupt gelöscht wird.> Wenn der auch nach deinem Aussprung aus deiner ISR noch ansteht (will> sagen Du musst den evtl. noch löschen - oder es steht ein anderer> freigegbener Iterrupt an, den du eben nicht löschst in dieser ISR) wäre> das auch eine Erklärung dafür, das deine LED nicht leuchtet. Die ISR> wird einfach dauernd ausgeführt...
Die LED wird aber eingeschaltet bevor überhaupt irgendein Interrupt
aktiviert ist. Der Interrupt wird ja erst aktiviert, nachdem die Ausgabe
in den Buffer geschrieben wurde und die LED wird beim Beschreiben des
Buffers eingeschaltet.
Hallo,
demnach hast du schon ein Problem mit dem Schreiben des ersten Byte.
Der code sieht aber so unverdächtig aus, das da nix passieren kann!
Es sei denn der Buffer liegt in einem Bereich, der mit
Funktionsregsistern überlappt, dann dürfte aber auch die LED 1 nicht
angehen!
Hast du das LED_On(2) schon mal in die ISR verlegt ?
Gruß,
THaala
THaala schrieb:> Hast du das LED_On(2) schon mal in die ISR verlegt ?
Nein noch nicht. Werd ich morgen machen. Das Board liegt leider am
Arbeitsplatz, wo ich heut net bin.
Hier mal die aktuelle Version. Nun funktioniert es. Ich weiß auch wo
der Fehler war, aber nicht was der Fehler war.
Der Fehler trat bei der Überprüfung von tx_reader bzw. tx_writer auf.
Die if-Anweisung, welche prüfen sollte, ob sich diese Variablen noch im
erlaubten Wertebereich befinden, verursachte wohl einen "crash". Nun wo
ich diese If-Abfragen durch Modulo-Operationen ersatz habe geht es.
Würde nur zu gern wissen warum.